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 }