99 "fmt"
1010 "math"
1111 "net"
12+ "net/url"
1213 "slices"
1314 "strconv"
1415 "strings"
@@ -35,18 +36,15 @@ import (
3536
3637const (
3738 // readerOwnerKeyPrefix is the key prefix in etcd for backend reader owner election.
38- // For global owner, the key is "/tiproxy/metric_reader/owner".
39- // For zonal owner, the key is "/tiproxy/metric_reader/{zone}/owner".
40- readerOwnerKeyPrefix = "/tiproxy/metric_reader"
39+ // For the default cluster, the key is "/tiproxy/metric_reader/owner".
40+ // For a named cluster, the key is "/tiproxy/metric_reader/{cluster}/owner".
4141 readerOwnerKeySuffix = "owner"
4242 // sessionTTL is the session's TTL in seconds for backend reader owner election.
4343 sessionTTL = 15
4444 // backendMetricPath is the path of backend HTTP API to read metrics.
4545 backendMetricPath = "/metrics"
46- // ownerMetricPath is the path of reading backend metrics from the backend reader owner.
47- ownerMetricPath = "/api/backend/metrics"
48- goPoolSize = 100
49- goMaxIdle = time .Minute
46+ goPoolSize = 100
47+ goMaxIdle = time .Minute
5048)
5149
5250var (
@@ -72,6 +70,7 @@ type BackendReader struct {
7270 marshalledHistory []byte
7371 cfgGetter config.ConfigGetter
7472 backendFetcher TopologyFetcher
73+ clusterName string
7574 lastZone string
7675 electionCfg elect.ElectionConfig
7776 election elect.Election
@@ -84,6 +83,11 @@ type BackendReader struct {
8483}
8584
8685func NewBackendReader (lg * zap.Logger , cfgGetter config.ConfigGetter , httpCli * http.Client , etcdCli * clientv3.Client ,
86+ backendFetcher TopologyFetcher , cfg * config.HealthCheck ) * BackendReader {
87+ return NewClusterBackendReader (lg , "" , cfgGetter , httpCli , etcdCli , backendFetcher , cfg )
88+ }
89+
90+ func NewClusterBackendReader (lg * zap.Logger , clusterName string , cfgGetter config.ConfigGetter , httpCli * http.Client , etcdCli * clientv3.Client ,
8791 backendFetcher TopologyFetcher , cfg * config.HealthCheck ) * BackendReader {
8892 return & BackendReader {
8993 queryRules : make (map [string ]QueryRule ),
@@ -92,6 +96,7 @@ func NewBackendReader(lg *zap.Logger, cfgGetter config.ConfigGetter, httpCli *ht
9296 lg : lg ,
9397 cfgGetter : cfgGetter ,
9498 backendFetcher : backendFetcher ,
99+ clusterName : strings .TrimSpace (clusterName ),
95100 cfg : cfg ,
96101 wgp : waitgroup .NewWaitGroupPool (goPoolSize , goMaxIdle ),
97102 electionCfg : elect .DefaultElectionConfig (sessionTTL ),
@@ -118,9 +123,9 @@ func (br *BackendReader) initElection(ctx context.Context, cfg *config.Config) e
118123 br .lastZone = cfg .GetLocation ()
119124 if len (br .lastZone ) > 0 {
120125 // Zonal owners are responsible for the backends in the same zone or not in any TiProxy zone.
121- key = fmt .Sprintf ("%s/%s/%s" , readerOwnerKeyPrefix , br .lastZone , readerOwnerKeySuffix )
126+ key = fmt .Sprintf ("%s/%s/%s" , readerOwnerKeyPrefix ( br . clusterName ) , br .lastZone , readerOwnerKeySuffix )
122127 } else {
123- key = fmt .Sprintf ("%s/%s" , readerOwnerKeyPrefix , readerOwnerKeySuffix )
128+ key = fmt .Sprintf ("%s/%s" , readerOwnerKeyPrefix ( br . clusterName ) , readerOwnerKeySuffix )
124129 }
125130 br .election = elect .NewElection (br .lg .Named ("elect" ), br .etcdCli , br .electionCfg , id , key , br )
126131 br .election .Start (ctx )
@@ -213,7 +218,8 @@ func (br *BackendReader) queryAllOwners(ctx context.Context) (zones, owners []st
213218 // Get all owner keys.
214219 opts := []clientv3.OpOption {clientv3 .WithPrefix ()}
215220 var kvs []* mvccpb.KeyValue
216- kvs , err = etcd .GetKVs (ctx , br .etcdCli , readerOwnerKeyPrefix , opts , br .electionCfg .Timeout , br .electionCfg .RetryIntvl , br .electionCfg .RetryCnt )
221+ keyPrefix := readerOwnerKeyPrefix (br .clusterName )
222+ kvs , err = etcd .GetKVs (ctx , br .etcdCli , keyPrefix , opts , br .electionCfg .Timeout , br .electionCfg .RetryIntvl , br .electionCfg .RetryCnt )
217223 if err != nil {
218224 return
219225 }
@@ -227,7 +233,7 @@ func (br *BackendReader) queryAllOwners(ctx context.Context) (zones, owners []st
227233 ownerMap := make (map [string ]ownerInfo )
228234 for _ , kv := range kvs {
229235 key := hack .String (kv .Key )
230- key = key [len (readerOwnerKeyPrefix ):]
236+ key = key [len (keyPrefix ):]
231237 if len (key ) == 0 || key [0 ] != '/' {
232238 continue
233239 }
@@ -466,7 +472,7 @@ func (br *BackendReader) GetBackendMetrics() []byte {
466472// If every member queries directly from backends, the backends may suffer from too much pressure.
467473func (br * BackendReader ) readFromOwner (ctx context.Context , ownerAddr string ) error {
468474 b := backoff .WithContext (backoff .WithMaxRetries (backoff .NewConstantBackOff (br .cfg .RetryInterval ), uint64 (br .cfg .MaxRetries )), ctx )
469- resp , err := br .httpCli .Get (ownerAddr , ownerMetricPath , b , br .cfg .DialTimeout )
475+ resp , err := br .httpCli .Get (ownerAddr , backendMetricOwnerPath ( br . clusterName ) , b , br .cfg .DialTimeout )
470476 if err != nil {
471477 return err
472478 }
@@ -570,6 +576,22 @@ func (br *BackendReader) Close() {
570576 }
571577}
572578
579+ func readerOwnerKeyPrefix (clusterName string ) string {
580+ clusterName = strings .TrimSpace (clusterName )
581+ if clusterName == "" || clusterName == config .DefaultBackendClusterName {
582+ return "/tiproxy/metric_reader"
583+ }
584+ return fmt .Sprintf ("/tiproxy/metric_reader/%s" , clusterName )
585+ }
586+
587+ func backendMetricOwnerPath (clusterName string ) string {
588+ clusterName = strings .TrimSpace (clusterName )
589+ if clusterName == "" {
590+ return "/api/backend/metrics"
591+ }
592+ return fmt .Sprintf ("/api/backend/metrics?cluster=%s" , url .QueryEscape (clusterName ))
593+ }
594+
573595func purgeHistory (history []model.SamplePair , retention time.Duration , now time.Time ) []model.SamplePair {
574596 idx := - 1
575597 for i := range history {
0 commit comments