github.com/polarismesh/polaris@v1.17.8/store/mysql/circuitbreaker_config_v2.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 sqldb 19 20 import ( 21 "database/sql" 22 "fmt" 23 "strconv" 24 "strings" 25 "time" 26 27 "github.com/polarismesh/polaris/common/model" 28 "github.com/polarismesh/polaris/store" 29 ) 30 31 const ( 32 labelCreateCircuitBreakerRule = "createCircuitBreakerRule" 33 labelUpdateCircuitBreakerRule = "updateCircuitBreakerRule" 34 labelDeleteCircuitBreakerRule = "deleteCircuitBreakerRule" 35 labelEnableCircuitBreakerRule = "enableCircuitBreakerRule" 36 ) 37 38 const ( 39 insertCircuitBreakerRuleSql = `insert into circuitbreaker_rule_v2( 40 id, name, namespace, enable, revision, description, level, src_service, src_namespace, 41 dst_service, dst_namespace, dst_method, config, ctime, mtime, etime) 42 values(?,?,?,?,?,?,?,?,?,?,?,?,?, sysdate(),sysdate(), %s)` 43 updateCircuitBreakerRuleSql = `update circuitbreaker_rule_v2 set name = ?, namespace=?, enable = ?, revision= ?, 44 description = ?, level = ?, src_service = ?, src_namespace = ?, 45 dst_service = ?, dst_namespace = ?, dst_method = ?, 46 config = ?, mtime = sysdate(), etime=%s where id = ?` 47 deleteCircuitBreakerRuleSql = `update circuitbreaker_rule_v2 set flag = 1, mtime = sysdate() where id = ?` 48 enableCircuitBreakerRuleSql = `update circuitbreaker_rule_v2 set enable = ?, revision = ?, mtime = sysdate(), 49 etime=%s where id = ?` 50 countCircuitBreakerRuleSql = `select count(*) from circuitbreaker_rule_v2 where flag = 0` 51 queryCircuitBreakerRuleFullSql = `select id, name, namespace, enable, revision, description, level, src_service, 52 src_namespace, dst_service, dst_namespace, dst_method, config, unix_timestamp(ctime), unix_timestamp(mtime), 53 unix_timestamp(etime) from circuitbreaker_rule_v2 where flag = 0` 54 queryCircuitBreakerRuleBriefSql = `select id, name, namespace, enable, revision, level, src_service, src_namespace, 55 dst_service, dst_namespace, dst_method, unix_timestamp(ctime), unix_timestamp(mtime), unix_timestamp(etime) 56 from circuitbreaker_rule_v2 where flag = 0` 57 queryCircuitBreakerRuleCacheSql = `select id, name, namespace, enable, revision, description, level, src_service, 58 src_namespace, dst_service, dst_namespace, dst_method, config, flag, unix_timestamp(ctime), 59 unix_timestamp(mtime), unix_timestamp(etime) from circuitbreaker_rule_v2 where mtime > FROM_UNIXTIME(?)` 60 ) 61 62 const ( 63 labelCreateCircuitBreakerRuleOld = "createCircuitBreakerRuleOld" 64 labelTagCircuitBreakerRuleOld = "tagCircuitBreakerRuleOld" 65 labelDeleteTagCircuitBreakerRuleOld = "deleteTagCircuitBreakerRuleOld" 66 labelReleaseCircuitBreakerRuleOld = "releaseCircuitBreakerRuleOld" 67 labelUnbindCircuitBreakerRuleOld = "unbindCircuitBreakerRuleOld" 68 labelUpdateCircuitBreakerRuleOld = "updateCircuitBreakerRuleOld" 69 labelDeleteCircuitBreakerRuleOld = "deleteCircuitBreakerRuleOld" 70 ) 71 72 // circuitBreakerStore 的实现 73 type circuitBreakerStore struct { 74 master *BaseDB 75 slave *BaseDB 76 } 77 78 func (c *circuitBreakerStore) CreateCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 79 err := RetryTransaction(labelCreateCircuitBreakerRule, func() error { 80 return c.createCircuitBreakerRule(cbRule) 81 }) 82 83 return store.Error(err) 84 } 85 86 func (c *circuitBreakerStore) createCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 87 return c.master.processWithTransaction(labelCreateCircuitBreakerRule, func(tx *BaseTx) error { 88 etimeStr := buildEtimeStr(cbRule.Enable) 89 str := fmt.Sprintf(insertCircuitBreakerRuleSql, etimeStr) 90 if _, err := tx.Exec(str, cbRule.ID, cbRule.Name, cbRule.Namespace, cbRule.Enable, cbRule.Revision, 91 cbRule.Description, cbRule.Level, cbRule.SrcService, cbRule.SrcNamespace, cbRule.DstService, 92 cbRule.DstNamespace, cbRule.DstMethod, cbRule.Rule); err != nil { 93 log.Errorf("[Store][database] fail to %s exec sql, err: %s", labelCreateCircuitBreakerRule, err.Error()) 94 return err 95 } 96 if err := tx.Commit(); err != nil { 97 log.Errorf("[Store][database] fail to %s commit tx, rule(%+v) commit tx err: %s", 98 labelCreateCircuitBreakerRule, cbRule, err.Error()) 99 return err 100 } 101 return nil 102 }) 103 } 104 105 // UpdateCircuitBreakerRule 更新熔断规则 106 func (c *circuitBreakerStore) UpdateCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 107 err := RetryTransaction(labelUpdateCircuitBreakerRule, func() error { 108 return c.updateCircuitBreakerRule(cbRule) 109 }) 110 111 return store.Error(err) 112 } 113 114 func (c *circuitBreakerStore) updateCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 115 return c.master.processWithTransaction(labelUpdateCircuitBreakerRule, func(tx *BaseTx) error { 116 etimeStr := buildEtimeStr(cbRule.Enable) 117 str := fmt.Sprintf(updateCircuitBreakerRuleSql, etimeStr) 118 if _, err := tx.Exec(str, cbRule.Name, cbRule.Namespace, cbRule.Enable, 119 cbRule.Revision, cbRule.Description, cbRule.Level, cbRule.SrcService, cbRule.SrcNamespace, 120 cbRule.DstService, cbRule.DstNamespace, cbRule.DstMethod, cbRule.Rule, cbRule.ID); err != nil { 121 log.Errorf("[Store][database] fail to %s exec sql, err: %s", labelUpdateCircuitBreakerRule, err.Error()) 122 return err 123 } 124 125 if err := tx.Commit(); err != nil { 126 log.Errorf("[Store][database] fail to %s commit tx, rule(%+v) commit tx err: %s", 127 labelUpdateCircuitBreakerRule, cbRule, err.Error()) 128 return err 129 } 130 131 return nil 132 }) 133 } 134 135 // DeleteCircuitBreakerRule 删除熔断规则 136 func (c *circuitBreakerStore) DeleteCircuitBreakerRule(id string) error { 137 err := RetryTransaction("deleteCircuitBreakerRule", func() error { 138 return c.deleteCircuitBreakerRule(id) 139 }) 140 141 return store.Error(err) 142 } 143 144 func (c *circuitBreakerStore) deleteCircuitBreakerRule(id string) error { 145 return c.master.processWithTransaction(labelDeleteCircuitBreakerRule, func(tx *BaseTx) error { 146 if _, err := tx.Exec(deleteCircuitBreakerRuleSql, id); err != nil { 147 log.Errorf( 148 "[Store][database] fail to %s exec sql, err: %s", labelDeleteCircuitBreakerRule, err.Error()) 149 return err 150 } 151 152 if err := tx.Commit(); err != nil { 153 log.Errorf("[Store][database] fail to %s commit tx, rule(%s) commit tx err: %s", 154 labelDeleteCircuitBreakerRule, id, err.Error()) 155 return err 156 } 157 return nil 158 }) 159 } 160 161 // HasCircuitBreakerRule check circuitbreaker rule exists 162 func (c *circuitBreakerStore) HasCircuitBreakerRule(id string) (bool, error) { 163 queryParams := map[string]string{"id": id} 164 count, err := c.getCircuitBreakerRulesCount(queryParams) 165 if nil != err { 166 return false, err 167 } 168 return count > 0, nil 169 } 170 171 // HasCircuitBreakerRuleByName check circuitbreaker rule exists by name 172 func (c *circuitBreakerStore) HasCircuitBreakerRuleByName(name string, namespace string) (bool, error) { 173 queryParams := map[string]string{exactName: name, "namespace": namespace} 174 count, err := c.getCircuitBreakerRulesCount(queryParams) 175 if nil != err { 176 return false, err 177 } 178 return count > 0, nil 179 } 180 181 // HasCircuitBreakerRuleByNameExcludeId check circuitbreaker rule exists by name exclude id 182 func (c *circuitBreakerStore) HasCircuitBreakerRuleByNameExcludeId( 183 name string, namespace string, id string) (bool, error) { 184 queryParams := map[string]string{exactName: name, "namespace": namespace, excludeId: id} 185 count, err := c.getCircuitBreakerRulesCount(queryParams) 186 if nil != err { 187 return false, err 188 } 189 return count > 0, nil 190 } 191 192 func fetchCircuitBreakerRuleRows(rows *sql.Rows) ([]*model.CircuitBreakerRule, error) { 193 defer rows.Close() 194 var out []*model.CircuitBreakerRule 195 for rows.Next() { 196 var cbRule model.CircuitBreakerRule 197 var flag int 198 var ctime, mtime, etime int64 199 err := rows.Scan(&cbRule.ID, &cbRule.Name, &cbRule.Namespace, &cbRule.Enable, &cbRule.Revision, 200 &cbRule.Description, &cbRule.Level, &cbRule.SrcService, &cbRule.SrcNamespace, &cbRule.DstService, 201 &cbRule.DstNamespace, &cbRule.DstMethod, &cbRule.Rule, &flag, &ctime, &mtime, &etime) 202 if err != nil { 203 log.Errorf("[Store][database] fetch circuitbreaker rule scan err: %s", err.Error()) 204 return nil, err 205 } 206 cbRule.CreateTime = time.Unix(ctime, 0) 207 cbRule.ModifyTime = time.Unix(mtime, 0) 208 cbRule.EnableTime = time.Unix(etime, 0) 209 cbRule.Valid = true 210 if flag == 1 { 211 cbRule.Valid = false 212 } 213 out = append(out, &cbRule) 214 } 215 if err := rows.Err(); err != nil { 216 log.Errorf("[Store][database] fetch circuitbreaker rule next err: %s", err.Error()) 217 return nil, err 218 } 219 return out, nil 220 } 221 222 func (c *circuitBreakerStore) GetCircuitBreakerRules( 223 filter map[string]string, offset uint32, limit uint32) (uint32, []*model.CircuitBreakerRule, error) { 224 var out []*model.CircuitBreakerRule 225 var err error 226 227 bValue, ok := filter[briefSearch] 228 var isBrief = ok && strings.ToLower(bValue) == "true" 229 delete(filter, briefSearch) 230 231 if isBrief { 232 out, err = c.getBriefCircuitBreakerRules(filter, offset, limit) 233 } else { 234 out, err = c.getFullCircuitBreakerRules(filter, offset, limit) 235 } 236 if err != nil { 237 return 0, nil, err 238 } 239 num, err := c.getCircuitBreakerRulesCount(filter) 240 if err != nil { 241 return 0, nil, err 242 } 243 return num, out, nil 244 } 245 246 func (c *circuitBreakerStore) getBriefCircuitBreakerRules( 247 filter map[string]string, offset uint32, limit uint32) ([]*model.CircuitBreakerRule, error) { 248 queryStr, args := genCircuitBreakerRuleSQL(filter) 249 args = append(args, offset, limit) 250 str := queryCircuitBreakerRuleBriefSql + queryStr + ` order by mtime desc limit ?, ?` 251 252 rows, err := c.master.Query(str, args...) 253 if err != nil { 254 log.Errorf("[Store][database] query brief circuitbreaker rules err: %s", err.Error()) 255 return nil, err 256 } 257 out, err := fetchBriefCircuitBreakerRules(rows) 258 if err != nil { 259 return nil, err 260 } 261 return out, nil 262 } 263 264 var blurQueryKeys = map[string]bool{ 265 "name": true, 266 "description": true, 267 "srcService": true, 268 "srcNamespace": true, 269 "dstService": true, 270 "dstNamespace": true, 271 "dstMethod": true, 272 } 273 274 const ( 275 svcSpecificQueryKeyService = "service" 276 svcSpecificQueryKeyNamespace = "serviceNamespace" 277 exactName = "exactName" 278 excludeId = "excludeId" 279 ) 280 281 func placeholders(n int) string { 282 var b strings.Builder 283 for i := 0; i < n-1; i++ { 284 b.WriteString("?,") 285 } 286 if n > 0 { 287 b.WriteString("?") 288 } 289 return b.String() 290 } 291 292 func genCircuitBreakerRuleSQL(query map[string]string) (string, []interface{}) { 293 str := "" 294 args := make([]interface{}, 0, len(query)) 295 var svcNamespaceQueryValue string 296 var svcQueryValue string 297 for key, value := range query { 298 if len(value) == 0 { 299 continue 300 } 301 if key == svcSpecificQueryKeyService { 302 svcQueryValue = value 303 continue 304 } 305 if key == svcSpecificQueryKeyNamespace { 306 svcNamespaceQueryValue = value 307 continue 308 } 309 storeKey := toUnderscoreName(key) 310 if _, ok := blurQueryKeys[key]; ok { 311 str += fmt.Sprintf(" and %s like ?", storeKey) 312 args = append(args, "%"+value+"%") 313 } else if key == "enable" { 314 str += fmt.Sprintf(" and %s = ?", storeKey) 315 arg, _ := strconv.ParseBool(value) 316 args = append(args, arg) 317 } else if key == "level" { 318 tokens := strings.Split(value, ",") 319 str += fmt.Sprintf(" and %s in (%s)", storeKey, placeholders(len(tokens))) 320 for _, token := range tokens { 321 args = append(args, token) 322 } 323 } else if key == exactName { 324 str += " and name = ?" 325 args = append(args, value) 326 } else if key == excludeId { 327 str += " and id != ?" 328 args = append(args, value) 329 } else { 330 str += fmt.Sprintf(" and %s = ?", storeKey) 331 args = append(args, value) 332 } 333 } 334 if len(svcQueryValue) > 0 { 335 str += " and (dst_service = ? or dst_service = '*')" 336 args = append(args, svcQueryValue) 337 } 338 if len(svcNamespaceQueryValue) > 0 { 339 str += " and (dst_namespace = ? or dst_namespace = '*')" 340 args = append(args, svcNamespaceQueryValue) 341 } 342 return str, args 343 } 344 345 // fetchBriefRateLimitRows fetch the brief ratelimit list 346 func fetchBriefCircuitBreakerRules(rows *sql.Rows) ([]*model.CircuitBreakerRule, error) { 347 defer rows.Close() 348 var out []*model.CircuitBreakerRule 349 for rows.Next() { 350 var cbRule model.CircuitBreakerRule 351 var ctime, mtime, etime int64 352 err := rows.Scan(&cbRule.ID, &cbRule.Name, &cbRule.Namespace, &cbRule.Enable, &cbRule.Revision, 353 &cbRule.Level, &cbRule.SrcService, &cbRule.SrcNamespace, &cbRule.DstService, &cbRule.DstNamespace, 354 &cbRule.DstMethod, &ctime, &mtime, &etime) 355 if err != nil { 356 log.Errorf("[Store][database] fetch brief circuitbreaker rule scan err: %s", err.Error()) 357 return nil, err 358 } 359 cbRule.CreateTime = time.Unix(ctime, 0) 360 cbRule.ModifyTime = time.Unix(mtime, 0) 361 cbRule.EnableTime = time.Unix(etime, 0) 362 out = append(out, &cbRule) 363 } 364 if err := rows.Err(); err != nil { 365 log.Errorf("[Store][database] fetch brief circuitbreaker rule next err: %s", err.Error()) 366 return nil, err 367 } 368 return out, nil 369 } 370 371 func (c *circuitBreakerStore) getFullCircuitBreakerRules( 372 filter map[string]string, offset uint32, limit uint32) ([]*model.CircuitBreakerRule, error) { 373 queryStr, args := genCircuitBreakerRuleSQL(filter) 374 args = append(args, offset, limit) 375 str := queryCircuitBreakerRuleFullSql + queryStr + ` order by mtime desc limit ?, ?` 376 377 rows, err := c.master.Query(str, args...) 378 if err != nil { 379 log.Errorf("[Store][database] query brief circuitbreaker rules err: %s", err.Error()) 380 return nil, err 381 } 382 out, err := fetchFullCircuitBreakerRules(rows) 383 if err != nil { 384 return nil, err 385 } 386 return out, nil 387 } 388 389 func fetchFullCircuitBreakerRules(rows *sql.Rows) ([]*model.CircuitBreakerRule, error) { 390 defer rows.Close() 391 var out []*model.CircuitBreakerRule 392 for rows.Next() { 393 var cbRule model.CircuitBreakerRule 394 var ctime, mtime, etime int64 395 err := rows.Scan(&cbRule.ID, &cbRule.Name, &cbRule.Namespace, &cbRule.Enable, &cbRule.Revision, 396 &cbRule.Description, &cbRule.Level, &cbRule.SrcService, &cbRule.SrcNamespace, &cbRule.DstService, 397 &cbRule.DstNamespace, &cbRule.DstMethod, &cbRule.Rule, &ctime, &mtime, &etime) 398 if err != nil { 399 log.Errorf("[Store][database] fetch full circuitbreaker rule scan err: %s", err.Error()) 400 return nil, err 401 } 402 cbRule.CreateTime = time.Unix(ctime, 0) 403 cbRule.ModifyTime = time.Unix(mtime, 0) 404 cbRule.EnableTime = time.Unix(etime, 0) 405 out = append(out, &cbRule) 406 } 407 if err := rows.Err(); err != nil { 408 log.Errorf("[Store][database] fetch full circuitbreaker rule next err: %s", err.Error()) 409 return nil, err 410 } 411 return out, nil 412 } 413 414 func (c *circuitBreakerStore) getCircuitBreakerRulesCount(filter map[string]string) (uint32, error) { 415 queryStr, args := genCircuitBreakerRuleSQL(filter) 416 str := countCircuitBreakerRuleSql + queryStr 417 var total uint32 418 err := c.master.QueryRow(str, args...).Scan(&total) 419 switch { 420 case err == sql.ErrNoRows: 421 return 0, nil 422 case err != nil: 423 log.Errorf("[Store][database] get circuitbreaker rule count err: %s", err.Error()) 424 return 0, err 425 default: 426 } 427 return total, nil 428 } 429 430 // GetCircuitBreakerRulesForCache list circuitbreaker rules by query 431 func (c *circuitBreakerStore) GetCircuitBreakerRulesForCache( 432 mtime time.Time, firstUpdate bool) ([]*model.CircuitBreakerRule, error) { 433 str := queryCircuitBreakerRuleCacheSql 434 if firstUpdate { 435 str += " and flag != 1" 436 } 437 rows, err := c.slave.Query(str, timeToTimestamp(mtime)) 438 if err != nil { 439 log.Errorf("[Store][database] query circuitbreaker rules with mtime err: %s", err.Error()) 440 return nil, err 441 } 442 cbRules, err := fetchCircuitBreakerRuleRows(rows) 443 if err != nil { 444 return nil, err 445 } 446 return cbRules, nil 447 } 448 449 // EnableCircuitBreakerRule enable circuitbreaker rule 450 func (c *circuitBreakerStore) EnableCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 451 err := RetryTransaction("enableCircuitbreaker", func() error { 452 return c.enableCircuitBreakerRule(cbRule) 453 }) 454 455 return store.Error(err) 456 } 457 458 func (c *circuitBreakerStore) enableCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 459 return c.master.processWithTransaction(labelEnableCircuitBreakerRule, func(tx *BaseTx) error { 460 461 etimeStr := buildEtimeStr(cbRule.Enable) 462 str := fmt.Sprintf(enableCircuitBreakerRuleSql, etimeStr) 463 if _, err := tx.Exec(str, cbRule.Enable, cbRule.Revision, cbRule.ID); err != nil { 464 log.Errorf( 465 "[Store][database] fail to %s exec sql, err: %s", labelEnableCircuitBreakerRule, err.Error()) 466 return err 467 } 468 469 if err := tx.Commit(); err != nil { 470 log.Errorf("[Store][database] fail to %s commit tx, rule(%+v) commit tx err: %s", 471 labelEnableCircuitBreakerRule, cbRule, err.Error()) 472 return err 473 } 474 return nil 475 }) 476 }