Skip to content

客户端与一致性读取

This content is not available in your language yet.

client/v3 把 KV、Watch、Lease、Cluster 和 Maintenance 组合成一个 gRPC 客户端,并通过 endpoint 管理、resolver 和重试处理成员切换。它提供的是访问一致性存储的客户端语义,不只是连接池。

先给答案:client/v3 把 KV、Watch、Lease、Cluster 和 Maintenance 组合成一…

Section titled “先给答案:client/v3 把 KV、Watch、Lease、Cluster 和 Maintenance 组合成一…”

client/v3 把 KV、Watch、Lease、Cluster 和 Maintenance 组合成一个 gRPC 客户端,并通过 endpoint 管理、resolver 和重试处理成员切换。它提供的是访问一致性存储的客户端语义,不只是连接池。 正文沿“客户端组成 -> 一致性读取 -> endpoint 与长连接”展开:先确认入口和状态归属,再跟踪控制流或数据流的推进,最后落到对外可观察的结果。

主要失效边界集中在“serializable 读当强一致、Watch 断线只重连、固定连接一个 endpoint”这些场景。它们破坏的是容量、顺序、并发或生命周期前提;排查时应先确认状态是否仍由正确对象持有,再核对推进条件和清理路径。

clientv3.New
├─ grpc conn / resolver
├─ KV client: Get / Put / Txn
├─ Watch client: long-lived stream
├─ Lease client: KeepAlive stream
├─ endpoint picker / retry
└─ close all sub-clients

Client 和 New 位于 client/v3/client.go:51-118;KV、Watch、Lease facade 分别由 client/v3/kv.go:143-151、watch.go:252-256、lease.go:199-203 创建。

客户端的 Get 可以选择 serializable 或线性一致语义。线性一致读需要服务端通过 ReadIndex 确认 leader 的提交边界,并等待本节点应用到对应 index;serializable 读可以从任意成员本地读取,延迟更低但可能落后。

Watch 和 KeepAlive 都是长连接流,普通 RPC 的一次性重试不能简单套用。客户端需要在 stream 断开、leader 切换和 endpoint 不可用时重建流,并通过 revision 或 lease ID 维持语义连续性。

为什么客户端不自行“补齐”事件

Section titled “为什么客户端不自行“补齐”事件”

替代方案:Watch 断线后只重连,不重新读取当前状态。 为什么不行:断线窗口内可能漏掉事件,单纯重连只能保证之后的新事件。 正确做法:用最后已处理 revision 重新 Watch;若 revision 已 compact,则先读当前状态,再从新 revision 建立 Watch。

场景 风险 处理
serializable 读当强一致 读取旧值 需要明确 Serializable=false 的默认语义
Watch 断线只重连 漏事件 记录 revision 并重建/全量同步
固定连接一个 endpoint leader 切换不可用 配置多个 endpoint 和 resolver
KeepAlive 无 context goroutine/stream 泄漏 关闭 client 或 cancel context

客户端库必须暴露一致性、重试和恢复语义;否则使用者只能看到“RPC 成功/失败”,无法知道数据是否新、事件是否完整。

面试锚点

  • serializable read 和 linearizable read 的差异是什么?
  • Watch 断线如何避免丢事件?
  • endpoint picker 为什么不能只做 round-robin?