github.com/polarismesh/polaris@v1.17.8/cache/service/circuitbreaker.go (about)

     1  /**
     2   * Tencent is pleased to support the open source community by making Polaris available.
     3   *
     4   * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
     5   *
     6   * Licensed under the BSD 3-Clause License (the "License");
     7   * you may not use this file except in compliance with the License.
     8   * You may obtain a copy of the License at
     9   *
    10   * https://opensource.org/licenses/BSD-3-Clause
    11   *
    12   * Unless required by applicable law or agreed to in writing, software distributed
    13   * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
    14   * CONDITIONS OF ANY KIND, either express or implied. See the License for the
    15   * specific language governing permissions and limitations under the License.
    16   */
    17  
    18  package service
    19  
    20  import (
    21  	"crypto/sha1"
    22  	"fmt"
    23  	"sort"
    24  	"sync"
    25  	"time"
    26  
    27  	"go.uber.org/zap"
    28  	"golang.org/x/sync/singleflight"
    29  
    30  	types "github.com/polarismesh/polaris/cache/api"
    31  	"github.com/polarismesh/polaris/common/model"
    32  	"github.com/polarismesh/polaris/common/utils"
    33  	"github.com/polarismesh/polaris/store"
    34  )
    35  
    36  // circuitBreaker的实现
    37  type circuitBreakerCache struct {
    38  	*types.BaseCache
    39  
    40  	storage store.Store
    41  	// rules record id -> *model.CircuitBreakerRule
    42  	rules *utils.SyncMap[string, *model.CircuitBreakerRule]
    43  	// increment cache
    44  	// fetched service cache
    45  	// key1: namespace, key2: service
    46  	circuitBreakers map[string]map[string]*model.ServiceWithCircuitBreakerRules
    47  	// key1: namespace
    48  	nsWildcardRules map[string]*model.ServiceWithCircuitBreakerRules
    49  	// all rules are wildcard specific
    50  	allWildcardRules *model.ServiceWithCircuitBreakerRules
    51  	lock             sync.RWMutex
    52  
    53  	singleFlight singleflight.Group
    54  }
    55  
    56  // NewCircuitBreakerCache 返回一个操作CircuitBreakerCache的对象
    57  func NewCircuitBreakerCache(s store.Store, cacheMgr types.CacheManager) types.CircuitBreakerCache {
    58  	return &circuitBreakerCache{
    59  		BaseCache:       types.NewBaseCache(s, cacheMgr),
    60  		storage:         s,
    61  		rules:           utils.NewSyncMap[string, *model.CircuitBreakerRule](),
    62  		circuitBreakers: make(map[string]map[string]*model.ServiceWithCircuitBreakerRules),
    63  		nsWildcardRules: make(map[string]*model.ServiceWithCircuitBreakerRules),
    64  		allWildcardRules: model.NewServiceWithCircuitBreakerRules(model.ServiceKey{
    65  			Namespace: allMatched,
    66  			Name:      allMatched,
    67  		}),
    68  	}
    69  }
    70  
    71  // Initialize 实现Cache接口的函数
    72  func (c *circuitBreakerCache) Initialize(_ map[string]interface{}) error {
    73  	return nil
    74  }
    75  
    76  // Update 实现Cache接口的函数
    77  func (c *circuitBreakerCache) Update() error {
    78  	// 多个线程竞争,只有一个线程进行更新
    79  	_, err, _ := c.singleFlight.Do(c.Name(), func() (interface{}, error) {
    80  		return nil, c.DoCacheUpdate(c.Name(), c.realUpdate)
    81  	})
    82  	return err
    83  }
    84  
    85  func (c *circuitBreakerCache) realUpdate() (map[string]time.Time, int64, error) {
    86  	start := time.Now()
    87  	cbRules, err := c.storage.GetCircuitBreakerRulesForCache(c.LastFetchTime(), c.IsFirstUpdate())
    88  	if err != nil {
    89  		log.Errorf("[Cache][CircuitBreaker] cache update err:%s", err.Error())
    90  		return nil, -1, err
    91  	}
    92  	lastMtimes, upsert, del := c.setCircuitBreaker(cbRules)
    93  	log.Info("[Cache][CircuitBreaker] get more rules",
    94  		zap.Int("pull-from-store", len(cbRules)), zap.Int("upsert", upsert), zap.Int("delete", del),
    95  		zap.Time("last", c.LastMtime(c.Name())), zap.Duration("used", time.Since(start)))
    96  	return lastMtimes, int64(len(cbRules)), nil
    97  }
    98  
    99  // clear 实现Cache接口的函数
   100  func (c *circuitBreakerCache) Clear() error {
   101  	c.BaseCache.Clear()
   102  	c.lock.Lock()
   103  	c.allWildcardRules.Clear()
   104  	c.rules = utils.NewSyncMap[string, *model.CircuitBreakerRule]()
   105  	c.nsWildcardRules = make(map[string]*model.ServiceWithCircuitBreakerRules)
   106  	c.circuitBreakers = make(map[string]map[string]*model.ServiceWithCircuitBreakerRules)
   107  	c.lock.Unlock()
   108  	return nil
   109  }
   110  
   111  // name 实现资源名称
   112  func (c *circuitBreakerCache) Name() string {
   113  	return types.CircuitBreakerName
   114  }
   115  
   116  // GetCircuitBreakerConfig 根据serviceID获取熔断规则
   117  func (c *circuitBreakerCache) GetCircuitBreakerConfig(
   118  	name string, namespace string) *model.ServiceWithCircuitBreakerRules {
   119  	// check service specific
   120  	rules := c.checkServiceSpecificCache(name, namespace)
   121  	if nil != rules {
   122  		return rules
   123  	}
   124  	rules = c.checkNamespaceSpecificCache(namespace)
   125  	if nil != rules {
   126  		return rules
   127  	}
   128  	return c.allWildcardRules
   129  }
   130  
   131  func (c *circuitBreakerCache) checkServiceSpecificCache(
   132  	name string, namespace string) *model.ServiceWithCircuitBreakerRules {
   133  	c.lock.RLock()
   134  	defer c.lock.RUnlock()
   135  	svcRules, ok := c.circuitBreakers[namespace]
   136  	if ok {
   137  		return svcRules[name]
   138  	}
   139  	return nil
   140  }
   141  
   142  func (c *circuitBreakerCache) checkNamespaceSpecificCache(namespace string) *model.ServiceWithCircuitBreakerRules {
   143  	c.lock.RLock()
   144  	defer c.lock.RUnlock()
   145  	return c.nsWildcardRules[namespace]
   146  }
   147  
   148  func (c *circuitBreakerCache) reloadRevision(svcRules *model.ServiceWithCircuitBreakerRules) {
   149  	rulesCount := svcRules.CountCircuitBreakerRules()
   150  	if rulesCount == 0 {
   151  		svcRules.Revision = ""
   152  		return
   153  	}
   154  	revisions := make([]string, 0, rulesCount)
   155  	svcRules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   156  		revisions = append(revisions, rule.Revision)
   157  	})
   158  	sort.Strings(revisions)
   159  	h := sha1.New()
   160  	revision, err := types.ComputeRevisionBySlice(h, revisions)
   161  	if err != nil {
   162  		log.Errorf("[Server][Service][CircuitBreaker] compute revision service(%s) err: %s",
   163  			svcRules.Service, err.Error())
   164  		return
   165  	}
   166  	svcRules.Revision = revision
   167  }
   168  
   169  func (c *circuitBreakerCache) deleteAndReloadCircuitBreakerRules(
   170  	svcRules *model.ServiceWithCircuitBreakerRules, id string) {
   171  	svcRules.DelCircuitBreakerRule(id)
   172  	c.reloadRevision(svcRules)
   173  }
   174  
   175  func (c *circuitBreakerCache) deleteCircuitBreakerFromServiceCache(id string, svcKeys map[model.ServiceKey]bool) {
   176  	c.lock.Lock()
   177  	defer c.lock.Unlock()
   178  	if len(svcKeys) == 0 {
   179  		// all wildcard
   180  		c.deleteAndReloadCircuitBreakerRules(c.allWildcardRules, id)
   181  		for _, rules := range c.nsWildcardRules {
   182  			c.deleteAndReloadCircuitBreakerRules(rules, id)
   183  		}
   184  		for _, svcRules := range c.circuitBreakers {
   185  			for _, rules := range svcRules {
   186  				c.deleteAndReloadCircuitBreakerRules(rules, id)
   187  			}
   188  		}
   189  		return
   190  	}
   191  	svcToReloads := make(map[model.ServiceKey]bool)
   192  	for svcKey := range svcKeys {
   193  		if svcKey.Name == allMatched {
   194  			rules, ok := c.nsWildcardRules[svcKey.Namespace]
   195  			if ok {
   196  				c.deleteAndReloadCircuitBreakerRules(rules, id)
   197  			}
   198  			svcRules, ok := c.circuitBreakers[svcKey.Namespace]
   199  			if ok {
   200  				for svc := range svcRules {
   201  					svcToReloads[model.ServiceKey{Namespace: svcKey.Namespace, Name: svc}] = true
   202  				}
   203  			}
   204  		} else {
   205  			svcToReloads[svcKey] = true
   206  		}
   207  	}
   208  	if len(svcToReloads) > 0 {
   209  		for svcToReload := range svcToReloads {
   210  			svcRules, ok := c.circuitBreakers[svcToReload.Namespace]
   211  			if ok {
   212  				rules, ok := svcRules[svcToReload.Name]
   213  				if ok {
   214  					c.deleteAndReloadCircuitBreakerRules(rules, id)
   215  				}
   216  			}
   217  		}
   218  	}
   219  }
   220  
   221  func (c *circuitBreakerCache) storeAndReloadCircuitBreakerRules(
   222  	svcRules *model.ServiceWithCircuitBreakerRules, cbRule *model.CircuitBreakerRule) {
   223  	svcRules.AddCircuitBreakerRule(cbRule)
   224  	c.reloadRevision(svcRules)
   225  }
   226  
   227  func createAndStoreServiceWithCircuitBreakerRules(svcKey model.ServiceKey, key string,
   228  	values map[string]*model.ServiceWithCircuitBreakerRules) *model.ServiceWithCircuitBreakerRules {
   229  	rules := model.NewServiceWithCircuitBreakerRules(svcKey)
   230  	values[key] = rules
   231  	return rules
   232  }
   233  
   234  func (c *circuitBreakerCache) storeCircuitBreakerToServiceCache(
   235  	entry *model.CircuitBreakerRule, svcKeys map[model.ServiceKey]bool) {
   236  	c.lock.Lock()
   237  	defer c.lock.Unlock()
   238  
   239  	if len(svcKeys) == 0 {
   240  		// all wildcard
   241  		c.storeAndReloadCircuitBreakerRules(c.allWildcardRules, entry)
   242  		for _, rules := range c.nsWildcardRules {
   243  			c.storeAndReloadCircuitBreakerRules(rules, entry)
   244  		}
   245  		for _, svcRules := range c.circuitBreakers {
   246  			for _, rules := range svcRules {
   247  				c.storeAndReloadCircuitBreakerRules(rules, entry)
   248  			}
   249  		}
   250  		return
   251  	}
   252  	svcToReloads := make(map[model.ServiceKey]bool)
   253  	for svcKey := range svcKeys {
   254  		if svcKey.Name == allMatched {
   255  			var wildcardRules *model.ServiceWithCircuitBreakerRules
   256  			var ok bool
   257  			wildcardRules, ok = c.nsWildcardRules[svcKey.Namespace]
   258  			if !ok {
   259  				wildcardRules = createAndStoreServiceWithCircuitBreakerRules(svcKey, svcKey.Namespace, c.nsWildcardRules)
   260  				// add all exists wildcard rules
   261  				c.allWildcardRules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   262  					wildcardRules.AddCircuitBreakerRule(rule)
   263  				})
   264  			}
   265  			c.storeAndReloadCircuitBreakerRules(wildcardRules, entry)
   266  			svcRules, ok := c.circuitBreakers[svcKey.Namespace]
   267  			if ok {
   268  				for svc := range svcRules {
   269  					svcToReloads[model.ServiceKey{Namespace: svcKey.Namespace, Name: svc}] = true
   270  				}
   271  			}
   272  		} else {
   273  			svcToReloads[svcKey] = true
   274  		}
   275  	}
   276  	if len(svcToReloads) > 0 {
   277  		for svcToReload := range svcToReloads {
   278  			var rules *model.ServiceWithCircuitBreakerRules
   279  			var svcRules map[string]*model.ServiceWithCircuitBreakerRules
   280  			var ok bool
   281  			svcRules, ok = c.circuitBreakers[svcToReload.Namespace]
   282  			if !ok {
   283  				svcRules = make(map[string]*model.ServiceWithCircuitBreakerRules)
   284  				c.circuitBreakers[svcToReload.Namespace] = svcRules
   285  			}
   286  			rules, ok = svcRules[svcToReload.Name]
   287  			if !ok {
   288  				rules = createAndStoreServiceWithCircuitBreakerRules(svcToReload, svcToReload.Name, svcRules)
   289  				// add all exists wildcard rules
   290  				c.allWildcardRules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   291  					rules.AddCircuitBreakerRule(rule)
   292  				})
   293  				// add all namespace wildcard rules
   294  				nsRules, ok := c.nsWildcardRules[svcToReload.Namespace]
   295  				if ok {
   296  					nsRules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   297  						rules.AddCircuitBreakerRule(rule)
   298  					})
   299  				}
   300  			}
   301  			c.storeAndReloadCircuitBreakerRules(rules, entry)
   302  		}
   303  	}
   304  }
   305  
   306  const allMatched = "*"
   307  
   308  func getServicesInvolveByCircuitBreakerRule(cbRule *model.CircuitBreakerRule) map[model.ServiceKey]bool {
   309  	svcKeys := make(map[model.ServiceKey]bool)
   310  	addService := func(name string, namespace string) {
   311  		if len(name) == 0 && len(namespace) == 0 {
   312  			return
   313  		}
   314  		if name == allMatched && namespace == allMatched {
   315  			return
   316  		}
   317  		svcKeys[model.ServiceKey{
   318  			Namespace: namespace,
   319  			Name:      name,
   320  		}] = true
   321  	}
   322  	addService(cbRule.DstService, cbRule.DstNamespace)
   323  	return svcKeys
   324  }
   325  
   326  // setCircuitBreaker 更新store的数据到cache中
   327  func (c *circuitBreakerCache) setCircuitBreaker(
   328  	cbRules []*model.CircuitBreakerRule) (map[string]time.Time, int, int) {
   329  
   330  	if len(cbRules) == 0 {
   331  		return nil, 0, 0
   332  	}
   333  
   334  	var upsert, del int
   335  
   336  	lastMtime := c.LastMtime(c.Name()).Unix()
   337  
   338  	for _, cbRule := range cbRules {
   339  		if cbRule.ModifyTime.Unix() > lastMtime {
   340  			lastMtime = cbRule.ModifyTime.Unix()
   341  		}
   342  
   343  		oldRule, ok := c.rules.Load(cbRule.ID)
   344  		if ok {
   345  			// 对比规则前后绑定的服务是否出现了变化,清理掉之前所绑定的信息数据
   346  			if oldRule.IsServiceChange(cbRule) {
   347  				// 从老的规则中获取所有的 svcKeys 信息列表
   348  				svcKeys := getServicesInvolveByCircuitBreakerRule(oldRule)
   349  				log.Info("[Cache][CircuitBreaker] clean rule bind old service info",
   350  					zap.String("svc-keys", fmt.Sprintf("%#v", svcKeys)), zap.String("rule-id", cbRule.ID))
   351  				// 挨个清空
   352  				c.deleteCircuitBreakerFromServiceCache(cbRule.ID, svcKeys)
   353  			}
   354  		}
   355  		svcKeys := getServicesInvolveByCircuitBreakerRule(cbRule)
   356  		if !cbRule.Valid {
   357  			del++
   358  			c.rules.Delete(cbRule.ID)
   359  			c.deleteCircuitBreakerFromServiceCache(cbRule.ID, svcKeys)
   360  			continue
   361  		}
   362  		upsert++
   363  		c.rules.Store(cbRule.ID, cbRule)
   364  		c.storeCircuitBreakerToServiceCache(cbRule, svcKeys)
   365  	}
   366  
   367  	return map[string]time.Time{
   368  		c.Name(): time.Unix(lastMtime, 0),
   369  	}, upsert, del
   370  }
   371  
   372  // GetCircuitBreakerCount 获取熔断规则总数
   373  func (c *circuitBreakerCache) GetCircuitBreakerCount() int {
   374  	c.lock.RLock()
   375  	defer c.lock.RUnlock()
   376  
   377  	names := make(map[string]bool)
   378  	c.allWildcardRules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   379  		names[rule.Name] = true
   380  	})
   381  	for _, rules := range c.nsWildcardRules {
   382  		rules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   383  			names[rule.Name] = true
   384  		})
   385  	}
   386  	for _, values := range c.circuitBreakers {
   387  		for _, rules := range values {
   388  			rules.IterateCircuitBreakerRules(func(rule *model.CircuitBreakerRule) {
   389  				names[rule.Name] = true
   390  			})
   391  		}
   392  	}
   393  	return len(names)
   394  }