github.com/polarismesh/polaris@v1.17.8/store/mysql/instance.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 "errors" 23 "fmt" 24 "strings" 25 "time" 26 27 apiservice "github.com/polarismesh/specification/source/go/api/v1/service_manage" 28 "go.uber.org/zap" 29 30 "github.com/polarismesh/polaris/common/model" 31 "github.com/polarismesh/polaris/store" 32 ) 33 34 // instanceStore 实现了InstanceStore接口 35 type instanceStore struct { 36 master *BaseDB // 大部分操作都用主数据库 37 slave *BaseDB // 缓存相关的读取,请求到slave 38 } 39 40 // AddInstance 添加实例 41 func (ins *instanceStore) AddInstance(instance *model.Instance) error { 42 err := RetryTransaction("addInstance", func() error { 43 return ins.addInstance(instance) 44 }) 45 return store.Error(err) 46 } 47 48 // addInstance 49 func (ins *instanceStore) addInstance(instance *model.Instance) error { 50 tx, err := ins.master.Begin() 51 if err != nil { 52 log.Errorf("[Store][database] add instance tx begin err: %s", err.Error()) 53 return err 54 } 55 defer func() { _ = tx.Rollback() }() 56 57 // 新增数据之前,必须先清理老数据 58 if err := cleanInstance(tx, instance.ID()); err != nil { 59 return err 60 } 61 62 if err := addMainInstance(tx, instance); err != nil { 63 log.Errorf("[Store][database] add instance main insert err: %s", err.Error()) 64 return err 65 } 66 67 if err := addInstanceCheck(tx, instance); err != nil { 68 return err 69 } 70 71 if err := updateInstanceMeta(tx, instance); err != nil { 72 log.Errorf("[Store][database] add instance meta err: %s", err.Error()) 73 return err 74 } 75 76 if err := tx.Commit(); err != nil { 77 log.Errorf("[Store][database] add instance commit tx err: %s", err.Error()) 78 return err 79 } 80 81 return nil 82 } 83 84 // BatchAddInstances 批量增加实例 85 func (ins *instanceStore) BatchAddInstances(instances []*model.Instance) error { 86 87 err := RetryTransaction("batchAddInstances", func() error { 88 return ins.batchAddInstances(instances) 89 }) 90 return store.Error(err) 91 } 92 93 // batchAddInstances batch add instances 94 func (ins *instanceStore) batchAddInstances(instances []*model.Instance) error { 95 tx, err := ins.master.Begin() 96 if err != nil { 97 log.Errorf("[Store][database] batch add instances begin tx err: %s", err.Error()) 98 return err 99 } 100 defer func() { _ = tx.Rollback() }() 101 102 if err := batchAddMainInstances(tx, instances); err != nil { 103 log.Errorf("[Store][database] batch add main instances err: %s", err.Error()) 104 return err 105 } 106 if err := batchAddInstanceCheck(tx, instances); err != nil { 107 log.Errorf("[Store][database] batch add instance check err: %s", err.Error()) 108 return err 109 } 110 if err := batchDeleteInstanceMeta(tx, instances); err != nil { 111 log.Errorf("[Store][database] batch delete instance metadata err: %s", err.Error()) 112 return err 113 } 114 if err := batchAddInstanceMeta(tx, instances); err != nil { 115 log.Errorf("[Store][database] batch add instance metadata err: %s", err.Error()) 116 return err 117 } 118 119 if err := tx.Commit(); err != nil { 120 log.Errorf("[Store][database] batch add instance commit tx err: %s", err.Error()) 121 return err 122 } 123 124 return nil 125 } 126 127 // UpdateInstance 更新实例 128 func (ins *instanceStore) UpdateInstance(instance *model.Instance) error { 129 err := RetryTransaction("updateInstance", func() error { 130 return ins.updateInstance(instance) 131 }) 132 if err == nil { 133 return nil 134 } 135 136 serr := store.Error(err) 137 if store.Code(serr) == store.DuplicateEntryErr { 138 serr = store.NewStatusError(store.DataConflictErr, err.Error()) 139 } 140 return serr 141 } 142 143 // updateInstance update instance 144 func (ins *instanceStore) updateInstance(instance *model.Instance) error { 145 tx, err := ins.master.Begin() 146 if err != nil { 147 log.Errorf("[Store][database] update instance tx begin err: %s", err.Error()) 148 return err 149 } 150 defer func() { _ = tx.Rollback() }() 151 152 // 更新main表 153 if err := updateInstanceMain(tx, instance); err != nil { 154 log.Errorf("[Store][database] update instance main err: %s", err.Error()) 155 return err 156 } 157 // 更新health check表 158 if err := updateInstanceCheck(tx, instance); err != nil { 159 log.Errorf("[Store][database] update instance check err: %s", err.Error()) 160 return err 161 } 162 // 更新meta表 163 if err := updateInstanceMeta(tx, instance); err != nil { 164 log.Errorf("[Store][database] update instance meta err: %s", err.Error()) 165 return err 166 } 167 168 if err := tx.Commit(); err != nil { 169 log.Errorf("[Store][database] update instance commit tx err: %s", err.Error()) 170 return err 171 } 172 173 return nil 174 } 175 176 // CleanInstance 清理数据 177 func (ins *instanceStore) CleanInstance(instanceID string) error { 178 return RetryTransaction("cleanInstance", func() error { 179 return ins.master.processWithTransaction("cleanInstance", func(tx *BaseTx) error { 180 if err := cleanInstance(tx, instanceID); err != nil { 181 return err 182 } 183 184 if err := tx.Commit(); err != nil { 185 log.Errorf("[Store][database] clean instance commit tx err: %s", err.Error()) 186 return err 187 } 188 189 return nil 190 }) 191 }) 192 } 193 194 // cleanInstance 清理数据 195 func cleanInstance(tx *BaseTx, instanceID string) error { 196 log.Infof("[Store][database] clean instance(%s)", instanceID) 197 cleanIns := "delete from instance where id = ? and flag = 1" 198 if _, err := tx.Exec(cleanIns, instanceID); err != nil { 199 log.Errorf("[Store][database] clean instance(%s), err: %s", instanceID, err.Error()) 200 return store.Error(err) 201 } 202 cleanMeta := "delete from instance_metadata where id = ?" 203 if _, err := tx.Exec(cleanMeta, instanceID); err != nil { 204 log.Errorf("[Store][database] clean instance_metadata(%s), err: %s", instanceID, err.Error()) 205 return store.Error(err) 206 } 207 cleanCheck := "delete from health_check where id = ?" 208 if _, err := tx.Exec(cleanCheck, instanceID); err != nil { 209 log.Errorf("[Store][database] clean health_check(%s), err: %s", instanceID, err.Error()) 210 return store.Error(err) 211 } 212 return nil 213 } 214 215 // DeleteInstance 删除一个实例,删除实例实际上是把flag置为1 216 func (ins *instanceStore) DeleteInstance(instanceID string) error { 217 if instanceID == "" { 218 return errors.New("delete Instance Missing instance id") 219 } 220 return RetryTransaction("deleteInstance", func() error { 221 return ins.master.processWithTransaction("deleteInstance", func(tx *BaseTx) error { 222 str := "update instance set flag = 1, mtime = sysdate() where `id` = ?" 223 if _, err := tx.Exec(str, instanceID); err != nil { 224 return store.Error(err) 225 } 226 227 if err := tx.Commit(); err != nil { 228 log.Errorf("[Store][database] delete instance commit tx err: %s", err.Error()) 229 return err 230 } 231 232 return nil 233 }) 234 }) 235 } 236 237 // BatchDeleteInstances 批量删除实例 238 func (ins *instanceStore) BatchDeleteInstances(ids []interface{}) error { 239 return RetryTransaction("batchDeleteInstance", func() error { 240 return ins.master.processWithTransaction("batchDeleteInstance", func(tx *BaseTx) error { 241 if err := BatchOperation("delete-instance", ids, func(objects []interface{}) error { 242 if len(objects) == 0 { 243 return nil 244 } 245 str := `update instance set flag = 1, mtime = sysdate() where id in ( ` + PlaceholdersN(len(objects)) + `)` 246 _, err := tx.Exec(str, objects...) 247 return store.Error(err) 248 }); err != nil { 249 return err 250 } 251 252 if err := tx.Commit(); err != nil { 253 log.Errorf("[Store][database] batch delete instance commit tx err: %s", err.Error()) 254 return err 255 } 256 257 return nil 258 }) 259 }) 260 } 261 262 // GetInstance 获取单个实例详情,只返回有效的数据 263 func (ins *instanceStore) GetInstance(instanceID string) (*model.Instance, error) { 264 instance, err := ins.getInstance(instanceID) 265 if err != nil { 266 return nil, err 267 } 268 269 // 如果实例无效,则不返回 270 if instance != nil && !instance.Valid { 271 return nil, nil 272 } 273 274 return instance, nil 275 } 276 277 // BatchGetInstanceIsolate 检查实例是否存在 278 func (ins *instanceStore) BatchGetInstanceIsolate(ids map[string]bool) (map[string]bool, error) { 279 if len(ids) == 0 { 280 return nil, nil 281 } 282 283 str := "select id, isolate from instance where flag = 0 and id in(" + PlaceholdersN(len(ids)) + ")" 284 args := make([]interface{}, 0, len(ids)) 285 for key := range ids { 286 args = append(args, key) 287 } 288 instanceIsolate := make(map[string]bool, len(ids)) 289 rows, err := ins.master.Query(str, args...) 290 if err != nil { 291 log.Errorf("[Store][database] check instances existed query err: %s", err.Error()) 292 return nil, err 293 } 294 var idx string 295 var isolate int 296 for rows.Next() { 297 if err := rows.Scan(&idx, &isolate); err != nil { 298 log.Errorf("[Store][database] check instances existed scan err: %s", err.Error()) 299 return nil, err 300 } 301 instanceIsolate[idx] = model.Int2bool(isolate) 302 } 303 304 return instanceIsolate, nil 305 } 306 307 // GetInstancesBrief 批量获取实例的serviceID 308 func (ins *instanceStore) GetInstancesBrief(ids map[string]bool) (map[string]*model.Instance, error) { 309 if len(ids) == 0 { 310 return nil, nil 311 } 312 313 str := `select instance.id, host, port, name, namespace, token, IFNULL(platform_id,"") from service, instance 314 where instance.flag = 0 and service.flag = 0 315 and service.id = instance.service_id and instance.id in (` + PlaceholdersN(len(ids)) + ")" 316 args := make([]interface{}, 0, len(ids)) 317 for key := range ids { 318 args = append(args, key) 319 } 320 321 rows, err := ins.master.Query(str, args...) 322 if err != nil { 323 log.Errorf("[Store][database] get instances service token query err: %s", err.Error()) 324 return nil, err 325 } 326 defer rows.Close() 327 328 out := make(map[string]*model.Instance, len(ids)) 329 var item model.ExpandInstanceStore 330 var instance model.InstanceStore 331 item.ServiceInstance = &instance 332 for rows.Next() { 333 if err := rows.Scan(&instance.ID, &instance.Host, &instance.Port, 334 &item.ServiceName, &item.Namespace, &item.ServiceToken, &item.ServicePlatformID); err != nil { 335 log.Errorf("[Store][database] get instances service token scan err: %s", err.Error()) 336 return nil, err 337 } 338 339 out[instance.ID] = model.ExpandStore2Instance(&item) 340 } 341 342 return out, nil 343 } 344 345 // GetInstancesCount 获取有效的实例总数 346 func (ins *instanceStore) GetInstancesCount() (uint32, error) { 347 countStr := "select count(*) from instance where flag = 0" 348 var count uint32 349 var err error 350 Retry("query-instance-row", func() error { 351 err = ins.master.QueryRow(countStr).Scan(&count) 352 return err 353 }) 354 switch { 355 case err == sql.ErrNoRows: 356 return 0, nil 357 case err != nil: 358 log.Errorf("[Store][database] get instances count scan err: %s", err.Error()) 359 return 0, err 360 default: 361 } 362 363 return count, nil 364 } 365 366 // GetInstancesCountTx . 367 func (ins *instanceStore) GetInstancesCountTx(tx store.Tx) (uint32, error) { 368 dbTx, _ := tx.GetDelegateTx().(*BaseTx) 369 countStr := "select count(*) from instance where flag = 0" 370 var count uint32 371 var err error 372 Retry("query-instance-row", func() error { 373 err = dbTx.QueryRow(countStr).Scan(&count) 374 return err 375 }) 376 switch { 377 case err == sql.ErrNoRows: 378 return 0, nil 379 case err != nil: 380 log.Errorf("[Store][database] get instances count scan err: %s", err.Error()) 381 return 0, err 382 default: 383 } 384 385 return count, nil 386 } 387 388 // GetInstancesMainByService 根据服务和host获取实例 389 // @note 不包括metadata 390 func (ins *instanceStore) GetInstancesMainByService(serviceID, host string) ([]*model.Instance, error) { 391 // 只查询有效的服务实例 392 str := genInstanceSelectSQL() + " where service_id = ? and host = ? and flag = 0" 393 rows, err := ins.master.Query(str, serviceID, host) 394 if err != nil { 395 log.Errorf("[Store][database] get instances main query err: %s", err.Error()) 396 return nil, err 397 } 398 399 var out []*model.Instance 400 err = callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) { 401 out = append(out, model.Store2Instance(entry)) 402 return true, nil 403 }) 404 if err != nil { 405 log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error()) 406 return nil, err 407 } 408 409 return out, nil 410 } 411 412 // GetExpandInstances 根据过滤条件查看对应服务实例及数目 413 func (ins *instanceStore) GetExpandInstances(filter, metaFilter map[string]string, offset uint32, 414 limit uint32) (uint32, []*model.Instance, error) { 415 // 只查询有效的实例列表 416 filter["instance.flag"] = "0" 417 418 out, err := ins.getExpandInstances(filter, metaFilter, offset, limit) 419 if err != nil { 420 return 0, nil, err 421 } 422 423 num, err := ins.getExpandInstancesCount(filter, metaFilter) 424 if err != nil { 425 return 0, nil, err 426 } 427 return num, out, err 428 } 429 430 // getExpandInstances 根据过滤条件查看对应服务实例 431 func (ins *instanceStore) getExpandInstances(filter, metaFilter map[string]string, offset uint32, 432 limit uint32) ([]*model.Instance, error) { 433 // 这种情况意味着,不需要详细的数据,可以不用query了 434 if limit == 0 { 435 return make([]*model.Instance, 0), nil 436 } 437 _, isName := filter["name"] 438 _, isNamespace := filter["namespace"] 439 _, isHost := filter["host"] 440 needForceIndex := isName || isNamespace || isHost 441 442 str := genExpandInstanceSelectSQL(needForceIndex) 443 order := &Order{"instance.mtime", "desc"} 444 str, args := genWhereSQLAndArgs(str, filter, metaFilter, order, offset, limit) 445 446 rows, err := ins.master.Query(str, args...) 447 if err != nil { 448 log.Errorf("[Store][database] get instance by filters query err: %s, str: %s, args: %v", err.Error(), str, args) 449 return nil, err 450 } 451 452 out, err := ins.getRowExpandInstances(rows) 453 if err != nil { 454 log.Errorf("[Store][database] get row instances err: %s", err.Error()) 455 return nil, err 456 } 457 458 return out, nil 459 } 460 461 // getExpandInstancesCount 根据过滤条件查看对应服务实例的数目 462 func (ins *instanceStore) getExpandInstancesCount(filter, metaFilter map[string]string) (uint32, error) { 463 str := `select count(*) from instance ` 464 // 查询条件是否有service表中的字段 465 _, isName := filter["name"] 466 _, isNamespace := filter["namespace"] 467 if isName || isNamespace { 468 str += `inner join service on instance.service_id = service.id ` 469 } 470 str, args := genWhereSQLAndArgs(str, filter, metaFilter, nil, 0, 1) 471 472 var count uint32 473 var err error 474 Retry("query-instance-row", func() error { 475 err = ins.master.QueryRow(str, args...).Scan(&count) 476 return err 477 }) 478 switch { 479 case err == sql.ErrNoRows: 480 log.Errorf("[Store][database] no row with this expand instance filter") 481 return count, err 482 case err != nil: 483 log.Errorf("[Store][database] get expand instance count by filter err: %s", err.Error()) 484 return count, err 485 default: 486 return count, nil 487 } 488 } 489 490 // GetMoreInstances 根据mtime获取增量修改数据 491 // 这里会返回所有的数据的,包括valid=false的数据 492 // 对于首次拉取,firstUpdate=true,只会拉取flag!=1的数据 493 func (ins *instanceStore) GetMoreInstances(tx store.Tx, mtime time.Time, firstUpdate, needMeta bool, 494 serviceID []string) (map[string]*model.Instance, error) { 495 496 dbTx, _ := tx.GetDelegateTx().(*BaseTx) 497 if needMeta { 498 instances, err := ins.getMoreInstancesMainWithMeta(dbTx, mtime, firstUpdate, serviceID) 499 if err != nil { 500 return nil, err 501 } 502 return instances, nil 503 } 504 instances, err := ins.getMoreInstancesMain(dbTx, mtime, firstUpdate, serviceID) 505 if err != nil { 506 return nil, err 507 } 508 return instances, nil 509 } 510 511 // GetInstanceMeta 根据实例ID获取实例的metadata 512 func (ins *instanceStore) GetInstanceMeta(instanceID string) (map[string]string, error) { 513 str := "select `mkey`, `mvalue` from instance_metadata where id = ?" 514 rows, err := ins.master.Query(str, instanceID) 515 if err != nil { 516 log.Errorf("[Store][database] query instance meta err: %s", err.Error()) 517 return nil, err 518 } 519 defer rows.Close() 520 521 out := make(map[string]string) 522 var key, value string 523 for rows.Next() { 524 if err := rows.Scan(&key, &value); err != nil { 525 log.Errorf("[Store][database] get instance meta rows scan err: %s", err.Error()) 526 return nil, err 527 } 528 529 out[key] = value 530 } 531 if err := rows.Err(); err != nil { 532 log.Errorf("[Store][database] get instance meta rows next err: %s", err.Error()) 533 return nil, err 534 } 535 536 return out, nil 537 } 538 539 // SetInstanceHealthStatus 设置实例健康状态 540 func (ins *instanceStore) SetInstanceHealthStatus(instanceID string, flag int, revision string) error { 541 return RetryTransaction("setInstanceHealthStatus", func() error { 542 return ins.master.processWithTransaction("setInstanceHealthStatus", func(tx *BaseTx) error { 543 str := "update instance set health_status = ?, revision = ?, mtime = sysdate() where `id` = ?" 544 if _, err := tx.Exec(str, flag, revision, instanceID); err != nil { 545 return store.Error(err) 546 } 547 548 if err := tx.Commit(); err != nil { 549 log.Errorf("[Store][database] set instance health status commit tx err: %s", err.Error()) 550 return err 551 } 552 553 return nil 554 }) 555 }) 556 } 557 558 // BatchSetInstanceHealthStatus 批量设置健康状态 559 func (ins *instanceStore) BatchSetInstanceHealthStatus(ids []interface{}, isolate int, revision string) error { 560 return RetryTransaction("batchSetInstanceHealthStatus", func() error { 561 return ins.master.processWithTransaction("batchSetInstanceHealthStatus", func(tx *BaseTx) error { 562 if err := BatchOperation("set-instance-healthy", ids, func(objects []interface{}) error { 563 if len(objects) == 0 { 564 return nil 565 } 566 str := "update instance set health_status = ?, revision = ?, mtime = sysdate() where id in " 567 str += "(" + PlaceholdersN(len(objects)) + ")" 568 args := make([]interface{}, 0, len(objects)+2) 569 args = append(args, isolate) 570 args = append(args, revision) 571 args = append(args, objects...) 572 _, err := tx.Exec(str, args...) 573 return store.Error(err) 574 }); err != nil { 575 return err 576 } 577 578 if err := tx.Commit(); err != nil { 579 log.Errorf("[Store][database] batch set instance health status commit tx err: %s", err.Error()) 580 return err 581 } 582 583 return nil 584 }) 585 }) 586 } 587 588 // BatchSetInstanceIsolate 批量设置实例隔离状态 589 func (ins *instanceStore) BatchSetInstanceIsolate(ids []interface{}, isolate int, revision string) error { 590 return RetryTransaction("batchSetInstanceIsolate", func() error { 591 return ins.master.processWithTransaction("batchSetInstanceIsolate", func(tx *BaseTx) error { 592 if err := BatchOperation("set-instance-isolate", ids, func(objects []interface{}) error { 593 if len(objects) == 0 { 594 return nil 595 } 596 str := "update instance set isolate = ?, revision = ?, mtime = sysdate() where id in " 597 str += "(" + PlaceholdersN(len(objects)) + ")" 598 args := make([]interface{}, 0, len(objects)+2) 599 args = append(args, isolate) 600 args = append(args, revision) 601 args = append(args, objects...) 602 _, err := tx.Exec(str, args...) 603 return store.Error(err) 604 }); err != nil { 605 return err 606 } 607 608 if err := tx.Commit(); err != nil { 609 log.Errorf("[Store][database] batch set instance isolate commit tx err: %s", err.Error()) 610 return err 611 } 612 613 return nil 614 }) 615 }) 616 } 617 618 // BatchAppendInstanceMetadata 追加实例 metadata 619 func (ins *instanceStore) BatchAppendInstanceMetadata(requests []*store.InstanceMetadataRequest) error { 620 if len(requests) == 0 { 621 return nil 622 } 623 return ins.master.processWithTransaction("AppendInstanceMetadata", func(tx *BaseTx) error { 624 for i := range requests { 625 id := requests[i].InstanceID 626 revision := requests[i].Revision 627 metadata := requests[i].Metadata 628 str := "replace into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values" 629 values := make([]string, 0, len(metadata)) 630 args := make([]interface{}, 0, len(metadata)*3) 631 for k, v := range metadata { 632 values = append(values, "(?, ?, ?, sysdate(), sysdate())") 633 args = append(args, id, k, v) 634 } 635 str += strings.Join(values, ",") 636 if log.DebugEnabled() { 637 log.Debug("[Store][database] append instance metadata", zap.String("sql", str), zap.Any("args", args)) 638 } 639 if _, err := tx.Exec(str, args...); err != nil { 640 log.Errorf("[Store][database] append instance metadata err: %s", err.Error()) 641 return err 642 } 643 644 str = "update instance set revision = ?, mtime = sysdate() where id = ?" 645 if _, err := tx.Exec(str, revision, id); err != nil { 646 log.Errorf("[Store][database] append instance metadata update revision err: %s", err.Error()) 647 return err 648 } 649 } 650 return tx.Commit() 651 }) 652 } 653 654 // BatchRemoveInstanceMetadata 删除实例指定的 metadata 655 func (ins *instanceStore) BatchRemoveInstanceMetadata(requests []*store.InstanceMetadataRequest) error { 656 if len(requests) == 0 { 657 return nil 658 } 659 return ins.master.processWithTransaction("RemoveInstanceMetadata", func(tx *BaseTx) error { 660 for i := range requests { 661 id := requests[i].InstanceID 662 revision := requests[i].Revision 663 keys := requests[i].Keys 664 str := "delete from instance_metadata where id = ? and mkey in (%s)" 665 values := make([]string, 0, len(keys)) 666 args := make([]interface{}, 0, 1+len(keys)) 667 args = append(args, id) 668 for i := range keys { 669 key := keys[i] 670 values = append(values, "?") 671 args = append(args, key) 672 } 673 str = fmt.Sprintf(str, strings.Join(values, ",")) 674 675 if _, err := tx.Exec(str, args...); err != nil { 676 log.Errorf("[Store][database] remove instance metadata by keys err: %s", err.Error()) 677 return err 678 } 679 680 str = "update instance set revision = ?, mtime = sysdate() where id = ?" 681 if _, err := tx.Exec(str, revision, id); err != nil { 682 log.Errorf("[Store][database] remove instance metadata by keys update revision err: %s", err.Error()) 683 return err 684 } 685 } 686 return tx.Commit() 687 }) 688 } 689 690 // getInstance 内部获取instance函数,根据instanceID,直接读取元数据,不做其他过滤 691 func (ins *instanceStore) getInstance(instanceID string) (*model.Instance, error) { 692 str := genInstanceSelectSQL() + " where instance.id = ?" 693 rows, err := ins.master.Query(str, instanceID) 694 if err != nil { 695 log.Errorf("[Store][database] get instance query err: %s", err.Error()) 696 return nil, err 697 } 698 699 out, err := fetchInstanceRows(rows) 700 if err != nil { 701 return nil, err 702 } 703 704 if len(out) == 0 { 705 return nil, err 706 } 707 708 meta, err := ins.GetInstanceMeta(out[0].ID()) 709 if err != nil { 710 return nil, err 711 } 712 out[0].MallocProto() 713 out[0].Proto.Metadata = meta 714 715 return out[0], nil 716 } 717 718 // getMoreInstancesMainWithMeta 获取增量instance+healthcheck+meta内容 719 // @note ro库有多个实例,且主库到ro库各实例的同步时间不一致。为避免获取不到meta,需要采用一条sql语句获取全部数据 720 func (ins *instanceStore) getMoreInstancesMainWithMeta(tx *BaseTx, mtime time.Time, firstUpdate bool, serviceID []string) ( 721 map[string]*model.Instance, error) { 722 // 首次拉取 723 if firstUpdate { 724 // 获取全量服务实例 725 instances, err := ins.getMoreInstancesMain(tx, mtime, firstUpdate, serviceID) 726 if err != nil { 727 log.Errorf("[Store][database] get more instance main err: %s", err.Error()) 728 return nil, err 729 } 730 // 获取全量服务实例元数据 731 str := "select id, mkey, mvalue from instance_metadata" 732 rows, err := tx.Query(str) 733 if err != nil { 734 log.Errorf("[Store][database] acquire instances meta query err: %s", err.Error()) 735 return nil, err 736 } 737 if err := fetchInstanceMetaRows(instances, rows); err != nil { 738 return nil, err 739 } 740 return instances, nil 741 } 742 743 // 非首次拉取 744 str := genCompleteInstanceSelectSQL() + " where instance.mtime >= FROM_UNIXTIME(?)" 745 args := make([]interface{}, 0, len(serviceID)+1) 746 args = append(args, timeToTimestamp(mtime)) 747 748 if len(serviceID) > 0 { 749 str += " and service_id in (" + PlaceholdersN(len(serviceID)) 750 str += ")" 751 } 752 for _, id := range serviceID { 753 args = append(args, id) 754 } 755 756 rows, err := ins.slave.Query(str, args...) 757 if err != nil { 758 log.Errorf("[Store][database] get more instance query err: %s", err.Error()) 759 return nil, err 760 } 761 return fetchInstanceWithMetaRows(rows) 762 } 763 764 // fetchInstanceWithMetaRows 获取instance main+health_check+instance_metadata rows里面的数据 765 func fetchInstanceWithMetaRows(rows *sql.Rows) (map[string]*model.Instance, error) { 766 if rows == nil { 767 return nil, nil 768 } 769 defer rows.Close() 770 771 out := make(map[string]*model.Instance) 772 var item model.InstanceStore 773 var id, mKey, mValue string 774 progress := 0 775 for rows.Next() { 776 progress++ 777 if progress%100000 == 0 { 778 log.Infof("[Store][database] instance+meta fetch rows progress: %d", progress) 779 } 780 if err := rows.Scan(&item.ID, &item.ServiceID, &item.VpcID, &item.Host, &item.Port, &item.Protocol, 781 &item.Version, &item.HealthStatus, &item.Isolate, &item.Weight, &item.EnableHealthCheck, 782 &item.LogicSet, &item.Region, &item.Zone, &item.Campus, &item.Priority, &item.Revision, 783 &item.Flag, &item.CheckType, &item.TTL, &id, &mKey, &mValue, 784 &item.CreateTime, &item.ModifyTime); err != nil { 785 log.Errorf("[Store][database] fetch instance+meta rows err: %s", err.Error()) 786 return nil, err 787 } 788 789 if _, ok := out[item.ID]; !ok { 790 out[item.ID] = model.Store2Instance(&item) 791 } 792 // 实例存在meta 793 if id != "" { 794 if out[item.ID].Proto.Metadata == nil { 795 out[item.ID].Proto.Metadata = make(map[string]string) 796 } 797 out[item.ID].Proto.Metadata[mKey] = mValue 798 } 799 } 800 if err := rows.Err(); err != nil { 801 log.Errorf("[Store][database] fetch instance+metadata rows next err: %s", err.Error()) 802 return nil, err 803 } 804 return out, nil 805 } 806 807 // getMoreInstancesMain 获取增量instances 主表内容,health_check内容 808 func (ins *instanceStore) getMoreInstancesMain(tx *BaseTx, mtime time.Time, firstUpdate bool, 809 serviceID []string) (map[string]*model.Instance, error) { 810 811 str := genInstanceSelectSQL() + " where instance.mtime >= FROM_UNIXTIME(?)" 812 args := make([]interface{}, 0, len(serviceID)+1) 813 args = append(args, timeToTimestamp(mtime)) 814 815 if firstUpdate { 816 str += " and flag != 1" 817 } 818 819 if len(serviceID) > 0 { 820 str += " and service_id in (" + PlaceholdersN(len(serviceID)) 821 str += ")" 822 } 823 for _, id := range serviceID { 824 args = append(args, id) 825 } 826 827 rows, err := tx.Query(str, args...) 828 if err != nil { 829 log.Errorf("[Store][database] get more instance query err: %s", err.Error()) 830 return nil, err 831 } 832 833 out := make(map[string]*model.Instance) 834 err = callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) { 835 out[entry.ID] = model.Store2Instance(entry) 836 return true, nil 837 }) 838 if err != nil { 839 log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error()) 840 return nil, err 841 } 842 843 return out, nil 844 } 845 846 // getRowExpandInstances 根据rows获取对应expandInstance 847 func (ins *instanceStore) getRowExpandInstances(rows *sql.Rows) ([]*model.Instance, error) { 848 out, err := fetchExpandInstanceRows(rows) 849 if err != nil { 850 return nil, err 851 } 852 853 data := make([]interface{}, 0, len(out)) 854 for idx := range out { 855 data = append(data, out[idx].Proto) 856 } 857 858 err = BatchQuery("expand-instance-metadata", data, func(objects []interface{}) error { 859 return ins.batchAcquireInstanceMetadata(objects) 860 }) 861 if err != nil { 862 log.Errorf("[Store][database] get expand instances metadata err: %s", err.Error()) 863 return nil, err 864 } 865 866 return out, nil 867 } 868 869 // batchAcquireInstanceMetadata 批量获取instance的metadata信息 870 // web端获取实例的数据的时候使用 871 func (ins *instanceStore) batchAcquireInstanceMetadata(instances []interface{}) error { 872 rows, err := batchQueryMetadata(ins.master.Query, instances) 873 if err != nil { 874 return err 875 } 876 if rows == nil { 877 return nil 878 } 879 defer rows.Close() 880 881 out := make(map[string]map[string]string) 882 var id, key, value string 883 for rows.Next() { 884 if err := rows.Scan(&id, &key, &value); err != nil { 885 log.Errorf("[Store][database] multi query instance metadata rows scan err: %s", err.Error()) 886 return err 887 } 888 if _, ok := out[id]; !ok { 889 out[id] = make(map[string]string) 890 } 891 out[id][key] = value 892 } 893 if err := rows.Err(); err != nil { 894 log.Errorf("[Store][database] multi query instance metadata rows next err: %s", err.Error()) 895 return err 896 } 897 898 // 把接收到的metadata,设置到instance中 899 // 这里会有两层循环,后续可以优化 TODO 900 for id, meta := range out { 901 for _, ele := range instances { 902 if id == ele.(*apiservice.Instance).GetId().GetValue() { 903 ele.(*apiservice.Instance).Metadata = meta 904 break 905 } 906 } 907 } 908 909 return nil 910 } 911 912 // batchQueryMetadata 批量查找metadata 913 func batchQueryMetadata(queryHandler QueryHandler, instances []interface{}) (*sql.Rows, error) { 914 if len(instances) == 0 { 915 return nil, nil 916 } 917 918 str := "select `id`, `mkey`, `mvalue` from instance_metadata where id in(" 919 first := true 920 args := make([]interface{}, 0, len(instances)) 921 for _, ele := range instances { 922 if first { 923 str += "?" 924 first = false 925 } else { 926 str += ",?" 927 } 928 args = append(args, ele.(*apiservice.Instance).GetId().GetValue()) 929 } 930 str += ")" 931 932 rows, err := queryHandler(str, args...) 933 if err != nil { 934 log.Errorf("[Store][database] multi query instance metadata err: %s", err.Error()) 935 return nil, err 936 } 937 938 return rows, nil 939 } 940 941 // addMainInstance 往instance主表中增加数据 942 func addMainInstance(tx *BaseTx, instance *model.Instance) error { 943 // #lizard forgives 944 str := `replace into instance(id, service_id, vpc_id, host, port, protocol, version, health_status, isolate, 945 weight, enable_health_check, logic_set, cmdb_region, cmdb_zone, cmdb_idc, priority, revision, ctime, mtime) 946 values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate(), sysdate())` 947 _, err := tx.Exec(str, instance.ID(), instance.ServiceID, instance.VpcID(), instance.Host(), instance.Port(), 948 instance.Protocol(), instance.Version(), instance.Healthy(), instance.Isolate(), instance.Weight(), 949 instance.EnableHealthCheck(), instance.LogicSet(), instance.Location().GetRegion().GetValue(), 950 instance.Location().GetZone().GetValue(), instance.Location().GetCampus().GetValue(), 951 instance.Priority(), instance.Revision()) 952 return err 953 } 954 955 // batchAddMainInstances 批量增加main instance数据 956 func batchAddMainInstances(tx *BaseTx, instances []*model.Instance) error { 957 str := `replace into instance(id, service_id, vpc_id, host, port, protocol, version, health_status, isolate, 958 weight, enable_health_check, logic_set, cmdb_region, cmdb_zone, cmdb_idc, priority, revision, ctime, mtime) 959 values` 960 first := true 961 args := make([]interface{}, 0) 962 for _, entry := range instances { 963 if !first { 964 str += "," 965 } 966 str += "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, sysdate(), sysdate())" 967 first = false 968 args = append(args, entry.ID(), entry.ServiceID, entry.VpcID(), entry.Host(), entry.Port()) 969 args = append(args, entry.Protocol(), entry.Version(), entry.Healthy(), entry.Isolate(), 970 entry.Weight()) 971 args = append(args, entry.EnableHealthCheck(), entry.LogicSet(), 972 entry.Location().GetRegion().GetValue(), entry.Location().GetZone().GetValue(), 973 entry.Location().GetCampus().GetValue(), entry.Priority(), entry.Revision()) 974 } 975 _, err := tx.Exec(str, args...) 976 return err 977 } 978 979 // addInstanceCheck 往health_check加入健康检查信息 980 func addInstanceCheck(tx *BaseTx, instance *model.Instance) error { 981 check := instance.HealthCheck() 982 if check == nil { 983 return nil 984 } 985 986 str := "replace into health_check(`id`, `type`, `ttl`) values(?, ?, ?)" 987 _, err := tx.Exec(str, instance.ID(), check.GetType(), 988 check.GetHeartbeat().GetTtl().GetValue()) 989 return err 990 } 991 992 // batchAddInstanceCheck 批量增加healthCheck数据 993 func batchAddInstanceCheck(tx *BaseTx, instances []*model.Instance) error { 994 str := "replace into health_check(`id`, `type`, `ttl`) values" 995 first := true 996 args := make([]interface{}, 0) 997 for _, entry := range instances { 998 if entry.HealthCheck() == nil { 999 continue 1000 } 1001 if !first { 1002 str += "," 1003 } 1004 str += "(?,?,?)" 1005 first = false 1006 args = append(args, entry.ID(), entry.HealthCheck().GetType(), 1007 entry.HealthCheck().GetHeartbeat().GetTtl().GetValue()) 1008 } 1009 // 不存在健康检查信息,直接返回 1010 if first { 1011 return nil 1012 } 1013 _, err := tx.Exec(str, args...) 1014 return err 1015 } 1016 1017 // addInstanceMeta 往表中加入instance meta数据 1018 func addInstanceMeta(tx *BaseTx, id string, meta map[string]string) error { 1019 if len(meta) == 0 { 1020 return nil 1021 } 1022 1023 str := "insert into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values " 1024 args := make([]interface{}, 0, len(meta)*3) 1025 cnt := 0 1026 for key, value := range meta { 1027 cnt++ 1028 if cnt == len(meta) { 1029 str += "(?, ?, ?, sysdate(), sysdate())" 1030 } else { 1031 str += "(?, ?, ?, sysdate(), sysdate()), " 1032 } 1033 1034 args = append(args, id) 1035 args = append(args, key) 1036 args = append(args, value) 1037 } 1038 1039 _, err := tx.Exec(str, args...) 1040 return err 1041 } 1042 1043 // batchDeleteInstanceMeta 批量删除metadata数据 1044 func batchDeleteInstanceMeta(tx *BaseTx, instances []*model.Instance) error { 1045 ids := make([]interface{}, 0, len(instances)) 1046 builder := strings.Builder{} 1047 for _, entry := range instances { 1048 // If instance is first registration, no need to participate in the following METADATA cleaning action 1049 // if entry.FirstRegis { 1050 // continue 1051 // } 1052 1053 ids = append(ids, entry.ID()) 1054 1055 if len(ids) > 1 { 1056 builder.WriteString(",") 1057 } 1058 builder.WriteString("?") 1059 } 1060 1061 if len(ids) == 0 { 1062 return nil 1063 } 1064 1065 str := `delete from instance_metadata where id in (` + builder.String() + `)` 1066 _, err := tx.Exec(str, ids...) 1067 return err 1068 } 1069 1070 // batchAddInstanceMeta 批量增加metadata数据 1071 func batchAddInstanceMeta(tx *BaseTx, instances []*model.Instance) error { 1072 str := "insert into instance_metadata(`id`, `mkey`, `mvalue`, `ctime`, `mtime`) values" 1073 args := make([]interface{}, 0) 1074 first := true 1075 for _, entry := range instances { 1076 if entry.Metadata() == nil || len(entry.Metadata()) == 0 { 1077 continue 1078 } 1079 1080 for key, value := range entry.Metadata() { 1081 if !first { 1082 str += "," 1083 } 1084 str += "(?, ?, ?, sysdate(), sysdate())" 1085 first = false 1086 args = append(args, entry.ID(), key, value) 1087 } 1088 } 1089 // 不存在metadata,直接返回 1090 if first { 1091 return nil 1092 } 1093 1094 _, err := tx.Exec(str, args...) 1095 return err 1096 } 1097 1098 // updateInstanceMeta 更新instance的meta表 1099 func updateInstanceMeta(tx *BaseTx, instance *model.Instance) error { 1100 // 只有metadata为nil的时候,则不用处理。 1101 // 如果metadata不为nil,但是len(metadata) == 0,则代表删除metadata 1102 meta := instance.Metadata() 1103 if meta == nil { 1104 return nil 1105 } 1106 1107 deleteStr := "delete from instance_metadata where id = ?" 1108 if _, err := tx.Exec(deleteStr, instance.ID()); err != nil { 1109 return err 1110 } 1111 return addInstanceMeta(tx, instance.ID(), meta) 1112 } 1113 1114 // updateInstanceCheck 更新instance的check表 1115 func updateInstanceCheck(tx *BaseTx, instance *model.Instance) error { 1116 // healthCheck为空,则删除 1117 check := instance.HealthCheck() 1118 if check == nil { 1119 return deleteInstanceCheck(tx, instance.ID()) 1120 } 1121 1122 str := "replace into health_check(id, type, ttl) values(?, ?, ?)" 1123 _, err := tx.Exec(str, instance.ID(), check.GetType(), 1124 check.GetHeartbeat().GetTtl().GetValue()) 1125 return err 1126 } 1127 1128 // updateInstanceMain 更新instance主表 1129 func updateInstanceMain(tx *BaseTx, instance *model.Instance) error { 1130 str := `update instance set protocol = ?, 1131 version = ?, health_status = ?, isolate = ?, weight = ?, enable_health_check = ?, logic_set = ?, 1132 cmdb_region = ?, cmdb_zone = ?, cmdb_idc = ?, priority = ?, revision = ?, mtime = sysdate() where id = ?` 1133 1134 _, err := tx.Exec(str, instance.Protocol(), instance.Version(), instance.Healthy(), instance.Isolate(), 1135 instance.Weight(), instance.EnableHealthCheck(), instance.LogicSet(), 1136 instance.Location().GetRegion().GetValue(), instance.Location().GetZone().GetValue(), 1137 instance.Location().GetCampus().GetValue(), instance.Priority(), 1138 instance.Revision(), instance.ID()) 1139 1140 return err 1141 } 1142 1143 // deleteInstanceCheck 删除healthCheck数据 1144 func deleteInstanceCheck(tx *BaseTx, id string) error { 1145 str := "delete from health_check where id = ?" 1146 _, err := tx.Exec(str, id) 1147 return err 1148 } 1149 1150 // fetchInstanceRows 获取instance rows的内容 1151 func fetchInstanceRows(rows *sql.Rows) ([]*model.Instance, error) { 1152 var out []*model.Instance 1153 err := callFetchInstanceRows(rows, func(entry *model.InstanceStore) (b bool, e error) { 1154 out = append(out, model.Store2Instance(entry)) 1155 return true, nil 1156 }) 1157 if err != nil { 1158 log.Errorf("[Store][database] call fetch instance rows err: %s", err.Error()) 1159 return nil, err 1160 } 1161 1162 return out, nil 1163 } 1164 1165 // callFetchInstanceRows 带回调的fetch instance 1166 func callFetchInstanceRows(rows *sql.Rows, callback func(entry *model.InstanceStore) (bool, error)) error { 1167 if rows == nil { 1168 return nil 1169 } 1170 defer rows.Close() 1171 var item model.InstanceStore 1172 progress := 0 1173 for rows.Next() { 1174 progress++ 1175 if progress%100000 == 0 { 1176 log.Infof("[Store][database] instance fetch rows progress: %d", progress) 1177 } 1178 err := rows.Scan(&item.ID, &item.ServiceID, &item.VpcID, &item.Host, &item.Port, &item.Protocol, 1179 &item.Version, &item.HealthStatus, &item.Isolate, &item.Weight, &item.EnableHealthCheck, 1180 &item.LogicSet, &item.Region, &item.Zone, &item.Campus, &item.Priority, &item.Revision, 1181 &item.Flag, &item.CheckType, &item.TTL, &item.CreateTime, &item.ModifyTime) 1182 if err != nil { 1183 log.Errorf("[Store][database] fetch instance rows err: %s", err.Error()) 1184 return err 1185 } 1186 ok, err := callback(&item) 1187 if err != nil { 1188 return err 1189 } 1190 if !ok { 1191 return nil 1192 } 1193 } 1194 if err := rows.Err(); err != nil { 1195 log.Errorf("[Store][database] instance rows catch err: %s", err.Error()) 1196 return err 1197 } 1198 1199 return nil 1200 } 1201 1202 // fetchExpandInstanceRows 获取expandInstance rows的内容 1203 func fetchExpandInstanceRows(rows *sql.Rows) ([]*model.Instance, error) { 1204 if rows == nil { 1205 return nil, nil 1206 } 1207 defer rows.Close() 1208 1209 var out []*model.Instance 1210 var item model.ExpandInstanceStore 1211 var instance model.InstanceStore 1212 item.ServiceInstance = &instance 1213 progress := 0 1214 for rows.Next() { 1215 progress++ 1216 if progress%50000 == 0 { 1217 log.Infof("[Store][database] expand instance fetch rows progress: %d", progress) 1218 } 1219 err := rows.Scan(&instance.ID, &instance.ServiceID, &instance.VpcID, &instance.Host, &instance.Port, 1220 &instance.Protocol, &instance.Version, &instance.HealthStatus, &instance.Isolate, 1221 &instance.Weight, &instance.EnableHealthCheck, &instance.LogicSet, &instance.Region, 1222 &instance.Zone, &instance.Campus, &instance.Priority, &instance.Revision, &instance.Flag, 1223 &instance.CheckType, &instance.TTL, &item.ServiceName, &item.Namespace, 1224 &instance.CreateTime, &instance.ModifyTime) 1225 if err != nil { 1226 log.Errorf("[Store][database] fetch instance rows err: %s", err.Error()) 1227 return nil, err 1228 } 1229 out = append(out, model.ExpandStore2Instance(&item)) 1230 } 1231 1232 if err := rows.Err(); err != nil { 1233 log.Errorf("[Store][database] instance rows catch err: %s", err.Error()) 1234 return nil, err 1235 } 1236 1237 return out, nil 1238 } 1239 1240 // fetchInstanceMetaRows 解析获取instance metadata 1241 func fetchInstanceMetaRows(instances map[string]*model.Instance, rows *sql.Rows) error { 1242 if rows == nil { 1243 return nil 1244 } 1245 defer rows.Close() 1246 var id, key, value string 1247 progress := 0 1248 for rows.Next() { 1249 progress++ 1250 if progress%500000 == 0 { 1251 log.Infof("[Store][database] fetch instance meta progress: %d", progress) 1252 } 1253 if err := rows.Scan(&id, &key, &value); err != nil { 1254 log.Errorf("[Store][database] fetch instance metadata rows scan err: %s", err.Error()) 1255 return err 1256 } 1257 // 不在目标列表,不存储 1258 if _, ok := instances[id]; !ok { 1259 continue 1260 } 1261 if instances[id].Proto.Metadata == nil { 1262 instances[id].Proto.Metadata = make(map[string]string) 1263 } 1264 instances[id].Proto.Metadata[key] = value 1265 } 1266 if err := rows.Err(); err != nil { 1267 log.Errorf("[Store][database] fetch instance metadata rows next err: %s", err.Error()) 1268 return err 1269 } 1270 1271 return nil 1272 } 1273 1274 // genInstanceSelectSQL 生成instance的select sql语句 1275 func genInstanceSelectSQL() string { 1276 str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""), 1277 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""), 1278 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, revision, flag, IFNULL(health_check.type, -1), 1279 IFNULL(health_check.ttl, 0), UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime) 1280 from instance left join health_check 1281 on instance.id = health_check.id ` 1282 return str 1283 } 1284 1285 // genCompleteInstanceSelectSQL 生成完整instance(主表+health_check+metadata)的sql语句 1286 func genCompleteInstanceSelectSQL() string { 1287 str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""), 1288 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""), 1289 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, revision, flag, IFNULL(health_check.type, -1), 1290 IFNULL(health_check.ttl, 0), IFNULL(instance_metadata.id, ""), IFNULL(mkey, ""), IFNULL(mvalue, ""), 1291 UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime) 1292 from instance 1293 left join health_check on instance.id = health_check.id 1294 left join instance_metadata on instance.id = instance_metadata.id ` 1295 return str 1296 } 1297 1298 // genExpandInstanceSelectSQL 生成expandInstance的select sql语句 1299 func genExpandInstanceSelectSQL(needForceIndex bool) string { 1300 str := `select instance.id, service_id, IFNULL(vpc_id,""), host, port, IFNULL(protocol, ""), IFNULL(version, ""), 1301 health_status, isolate, weight, enable_health_check, IFNULL(logic_set, ""), IFNULL(cmdb_region, ""), 1302 IFNULL(cmdb_zone, ""), IFNULL(cmdb_idc, ""), priority, instance.revision, instance.flag, 1303 IFNULL(health_check.type, -1), IFNULL(health_check.ttl, 0), service.name, service.namespace, 1304 UNIX_TIMESTAMP(instance.ctime), UNIX_TIMESTAMP(instance.mtime) 1305 from (service inner join instance ` 1306 if needForceIndex { 1307 str += `force index(service_id, host) ` 1308 } 1309 str += `on service.id = instance.service_id) left join health_check on instance.id = health_check.id ` 1310 return str 1311 }