这是一个创建于 52 天前的主题,其中的信息可能已经有所发展或是发生改变。
type Client struct {
Cluster
KV
Lease
Watcher
Auth
Maintenance
conn *grpc.ClientConn
cfg Config
creds grpccredentials.TransportCredentials
resolver *resolver.EtcdManualResolver
mu *sync.RWMutex
ctx context.Context
cancel context.CancelFunc
// Username is a user name for authentication.
Username string
// Password is a password for authentication.
Password string
authTokenBundle credentials.Bundle
callOpts []grpc.CallOption
lgMu *sync.RWMutex
lg *zap.Logger
}
func newClient(cfg *Config) (*Client, error) {
.....
client.Cluster = NewCluster(client)
client.KV = NewKV(client)
client.Lease = NewLease(client)
client.Watcher = NewWatcher(client)
client.Auth = NewAuth(client)
client.Maintenance = NewMaintenance(client)
....
}
// NewLease 创建一个新的 Lease 实例。
func NewLease(client *clientv3.Client, purpose string) *Lease {
// 返回一个 Lease 结构体的指针。
return &Lease{
// 设置选举目的。
Purpose: purpose,
// 传入 etcd 客户端。
client: client,
// 基于主客户端创建一个专门用于租约操作的客户端。
lease: clientv3.NewLease(client),
}
}
在这个代码中,我记得一个 client 在构建的时候,会调用 newClient()通过配置好的 cfg 创建一个 client 结构体对象。那么,内部的接口已经赋值了具体的 Lease 对象“client.Lease = NewLease(client)”.
这个 NewLease 的实现是 TiDB 中的代码,代码中大量使用这种类似“职责分离”的逻辑,就是明明已经有了一个 etcd 的 client 对象了,还要额外再创加一个专门的 lease 的客户端对象。
这种代码实践是一种生产中是一种类似“最佳实践”的做法吗。
这种专门再创建一个 lease ,我能想到的理由如下:
1. 职责分离,不同的功能客户端负责各自的操作
2. 传进来的 client 可能只是一个声明好的空结构体,内部没有进行赋值。
不知道有没有看过 tidb 的大佬解惑这种设计。
2 条回复 • 2025-06-11 21:05:43 +08:00
 |
|
1
Reficul 52 天前
具体没读过 TIDB 的代码,但是可能有几个好处: 1. 不同 Client 可能配置不一样; 2. 不同 Client 可以隔离连接。因为 GRPC 下面是 http/2 ,有时候多路复用在同一个 tcp 连接容易可能会引起问题,比如大请求饿死或者引起小请求的延迟。
|