etcd 3.1 系列发行说明深度解读:read-index 线性化读加速、选举 tick 控制与可观测性指标演进
etcd 3.1 系列(v3.1.0 至 v3.1.21,2017-01 至 2019 年)是从 v3.0 迈向生产成熟度的关键版本线:它在主干引入了 Raft read-index 加速线性化读、稳定化 v3 认证 API,并在后续补丁版本中围绕选举 tick 控制、快照/watcher 稳定性与 Prometheus 指标体系做了一连串精细化修复与增强。本文基于 CHANGELOG-3.1.md 逐版本梳理这一完整演进脉络,并结合当前仓库源码印证 read-index 时代的选举快进机制、快照一致性校验与客户端租约保活等关键实现,帮助读者理解这些变更背后的设计动机与实际影响,从而为版本选择、故障排查与升级决策提供可靠依据。
版本全景:3.1 系列覆盖的发布谱系
CHANGELOG 收录的 3.1.x 版本按时间从旧到新共 20 个条目,编译所用 Go 工具链也从 Go 1.7.4 逐步演进到 Go 1.8.7:
| 版本 | 发布日期 | 核心主题 | 编译 Go 版本 |
|---|---|---|---|
| v3.1.0 | 2017-01-20 | read-index 线性化读、认证 API 稳定、新 flag 与 gRPC Proxy | Go 1.7.4 |
| v3.1.1 | 2017-02-17 | 工具链升级 | Go 1.7.5 |
| v3.1.2 | 2017-02-24 | gateway 多端点修复、默认 IPv4 host | Go 1.7.5 |
| v3.1.3 | 2017-03-10 | gateway/gRPC Proxy 的 sd_notify 修复 | Go 1.7.5 |
| v3.1.4 | 2017-03-22 | 工具链升级 | Go 1.7.5 |
| v3.1.5 | 2017-03-27 | raft 内存泄漏修复、Windows 路径修复 | Go 1.7.5 |
| v3.1.6 | 2017-04-19 | Auth API 响应头、Status API 去鉴权 | Go 1.7.5 |
| v3.1.7 | 2017-04-28 | 工具链升级 | Go 1.7.5 |
| v3.1.8 | 2017-05-19 | 工具链升级 | Go 1.7.5 |
| v3.1.9 | 2017-06-09 | 允许超过 512MB 的 v2 快照 | Go 1.7.6 |
| v3.1.10 | 2017-07-14 | Docker 镜像增加 minor 版本 tag | Go 1.8.3 |
| v3.1.11 | 2017-11-28 | 回移 mvcc restore 事件发送与 bbolt 修复 | Go 1.8.5 |
| v3.1.12 | 2018-03-08 | unsynced watcher 恢复修复 | Go 1.8.7 |
| v3.1.13 | 2018-03-29 | 重启时选举超时调整 | Go 1.8.7 |
| v3.1.14 | 2018-04-24 | 新增 --initial-election-tick-advance flag、etcd_server_is_leader 指标 |
Go 1.8.7 |
| v3.1.15 | 2018-05-09 | 按 --max-snapshots 清理旧 *.snap.db |
Go 1.8.7 |
| v3.1.16 | 2018-05-31 | 修复 mvcc 快照恢复导致的 panic | Go 1.8.7 |
| v3.1.17 | 2018-06-06 | v3 快照恢复(先落盘再加载) | Go 1.8.7 |
| v3.1.18 | 2018-06-15 | 新增 etcd_server_version 指标 |
Go 1.8.7 |
| v3.1.19 | 2018-07-24 | 存储尺寸/配额指标体系 | Go 1.8.7 |
| v3.1.20 | 2018-10-10 | 快照一致性校验、gRPC 调试拦截器、快照收发指标 | Go 1.8.7 |
| v3.1.21 | 2019(TBD) | etcdctl endpoint health 输出、db 压缩时长指标修复 | — |
更早的 v3.0 历史见 CHANGELOG-3.0.md。需要说明的是:3.1 系列发布于 2017–2019 年,文中对当前仓库源码的引用仅用于印证这些特性"现在长什么样",部分行为在后续版本中已演进(如 --max-snapshots 被移除),引用时需注意适用前提。
v3.1.0 奠基特性:read-index 线性化读与稳定认证
v3.1.0 是该系列最重要的版本,两大标志性改进如下:
1. 更快的线性化读(Raft read-index)
v3.1.0 实现了 Raft read-index 协议:只读请求不再需要走完整的 propose-commit 流程,leader 只需确认自己仍是 leader(通过任期编号与多数派回显的读索引机制)即可直接服务读请求。这是 etcd 读性能量级提升的基础,也是后续 v3.1.x 中"read index wait timeout 告警日志"(PR #10026)、etcd_server_slow_read_indexes_total、etcd_server_read_indexes_failed_total 等观测项存在的原因——它们都在监控 read-index 机制本身的健康度。
2. v3 认证 API 稳定化
v3 authentication API 自 v3.1.0 起标记为稳定(stable)。配套的安全细节变更包括:
- 未提供自定义 CA 时,SRV 记录(如
infra1.example.com)必须匹配 discovery 域名(example.com); TLSConfig.ServerName在用户证书场景下被忽略(为向后兼容保留,计划弃用);- 例如
etcd --discovery-srv=example.com只会在所提供证书的 SAN 字段包含根域example.com时才认证 peer/client。
3. 破坏性变更与依赖升级
- 弃用了 4 个自研 gRPC 指标,改用 go-grpc-prometheus 生态方案:
etcd_grpc_requests_total、etcd_grpc_requests_failed_total、etcd_grpc_active_streams、etcd_grpc_unary_requests_duration_seconds; - 依赖
github.com/ugorji/go/codec升级并重新生成 v2 client 代码。
4. 服务端行为与 flag 变化
- 新增
--log-output、--metricsflag;--strict-reconfig-check改为默认开启; - advertise URL 缺省时使用默认路由 IP;
- 集群拒绝会丢失 quorum 的 member 移除请求;
- discovery 等待重试引入上限;
- 通过域名绑定 listener 会告警(计划弃用);
- leader 主动下线时自动发生 leadership transfer。
5. 自动压缩(auto-compaction)语义
v3.0 与 v3.1 中 --auto-compaction-retention=10 的运行机制在 CHANGELOG 中被完整描述,值得保留为运维参考:
- Compactor 只支持周期性压缩(periodic compaction);
- 每 5 分钟记录一次最新 revision,直到到达第一个压缩周期(如 10 小时);
- 为保留上一个压缩周期的历史,它使用压缩周期开始前最后一次采集到的 revision(例如
--auto-compaction-retention=10时,用"10 小时前获取到的 revision 100"作为 compact revision); - 压缩成功或目标 revision 已被压缩后,重置周期计时器并重新开始采集 revision 记录;
- 压缩失败则 5 分钟后重试。
6. client v3 与 etcdctl v3 新能力
client v3 侧:新增 SetEndpoints(运行时更新端点)、Sync(自动更新端点)、Lease.TimeToLive API;用全局 logger 替换 Config.Logger 字段;Get API 响应默认按 key 升序排序。
etcdctl v3 侧:新增 lease timetolive 命令、get 命令的 --print-value-only flag、make-mirror 的 --dest-prefix flag,get 响应同样默认升序。
7. 实验性 gRPC Proxy
v3.1.0 引入了实验性的 gRPC proxy 功能(对应当前仓库 server/proxy/grpcproxy/ 目录),用于 v2 客户端平滑迁移到 v3。v3.1.2/v3.1.3 中多次修复了 gateway 多端点支持与 gateway、grpc-proxy 的 sd_notify 行为。
选举 tick 快进机制:从问题到可控 flag 的演进
3.1 系列中关于"重启/重加入时触发破坏性选举"的修复经历了三个版本,构成一个完整的调优故事:
v3.1.13(2018-03-29):服务端启动时选举超时的调整。此前 etcd 在服务启动时快进 election ticks,只留 1 个 tick 的选举窗口,以加速跨数据中心等大选超时场景下的启动阶段;但如果最后一个 tick 在 leader 联系上重启节点之前耗尽,就会触发破坏性选举,影响集群可用性。修复后,etcd 重启时会调整 election ticks 使剩余 tick 大于 1,给 leader 留出更多时间发送心跳。
v3.1.14(2018-04-24):新增 --initial-election-tick-advance flag,把该行为变成可配置项:
- 默认
--initial-election-tick-advance=true,本地 member 快进 election ticks 以加速"初始" leader 选举; - 典型收益:跨数据中心部署可能要求 10 秒的 election timeout,快进后节点无需等待满 10 秒(例如快进到 8 秒,只剩 2 秒即触发选举);
- 成立前提:集群无活跃 leader(快进加速选举),或集群已有 leader 且重加入 follower 大概率在选举超时前收到心跳;
- 风险:若 leader 到重加入 follower 的网络拥塞、剩余 tick 内收不到心跳,就会发生破坏性选举;
- 因此可用
--initial-election-tick-advance=false关闭,代价是跨数据中心初始 bootstrap 变慢; - 单节点集群无论该 flag 如何都执行快进。
当前仓库源码印证了这一机制的最终形态:
- flag 定义与默认值(
true)见 embed/config.go 与 embed/config.go,配置字段及注释见 config/config.go; - 启动时的快进逻辑见 etcdserver/server.go:单节点(
clusterN == 1)无条件执行advanceTicks(ElectionTicks-1);多节点场景下,若InitialElectionTickAdvance为false则直接跳过(打印 "skipping initial election tick advance"),否则先等待 peer 连接报告(间隔 50ms,上限rafthttp.ConnReadTimeout约 5 秒),确认有活跃 peer 后才继续快进——即 CHANGELOG 中"无活跃 peer 时快进无意义"的假设在代码中得到了落实。
快照与 watcher 稳定性修复链
3.1.x 中四个版本围绕"快照 + watch 恢复"修复了若干会导致丢事件甚至 panic 的问题,是理解 etcd 崩溃恢复语义的好材料:
v3.1.15 —— 尊重 --max-snapshots 清理旧快照:此前 etcd 未按 --max-snapshots 清理磁盘上的旧 *.snap.db 文件,修复后保留至多 --max-snapshots 个文件。值得注意的是,从当前仓库源码结构看,该 flag 在后续版本已被移除,改为固定常量 maxSnapDBFiles = 5(见 etcdserver/server.go 的注释:"It's no longer configurable now that --max-snapshots is removed")。
v3.1.12 —— 修复 "unsynced" watcher 恢复:"unsynced" watcher 指需要在与过去事件重新同步的慢 watcher(请求了较旧 revision 的 watcher)。典型场景:某节点带着一个指向未来 revision 的 watcher 发生网络分区,分区解除后 leader 向其发送快照;应用快照时,watch storage 会把当前 synced watchers 移入 unsynced 组(分区期间可能已过期)并重置组以重启 watcher 例程。旧代码在 synced → unsynced 迁移时未正确填充底层 watcher 组,导致客户端可能丢失事件。
v3.1.16 —— 修复 mvcc 恢复 panic:假设 watcher 请求了未来 revision X 并发往节点 A,随后 A 网络分区;分区期间集群继续推进,分区解除后 leader 向 A 发快照。旧逻辑下,若快照的最新 revision 仍低于 watch revision X,etcd server 会在快照恢复时直接 panic,该问题在 v3.1.16 修复。
v3.1.17 —— v3 快照先落盘再加载:follower 收到 leader 的快照并持久化为 [SNAPSHOT-INDEX].snap.db 文件。修复前,服务器不保证快照文件先写入磁盘再被加载;一旦 WAL 中出现比快照 index 更新却基于过期快照的条目,会发生 index 不匹配并触发 server panic。修复后,服务器确保收到快照先持久化到磁盘、然后再加载。
v3.1.20 —— 快照状态一致性校验:snapshot status 增加一致性检查,快照文件校验失败时返回 "snapshot file integrity check failed..." 错误。其底层机制在当前仓库中依然可见:服务端在发送快照流时同步计算 SHA-256 摘要,并在数据流末尾单独发送该摘要供恢复端校验,见 v3rpc/maintenance.go 中 "record SHA digest of snapshot data / used for integrity checks during snapshot restore operation" 的注释。
可观测性:3.1 系列补齐的 Prometheus 指标体系
CHANGELOG 每个版本的 "Metrics, Monitoring" 小节均提示:所有 etcd_debugging_* 前缀指标为实验性,可能随时变化。3.1 系列逐步补齐了如下生产级指标(按引入版本):
| 版本 | 新增指标 | 用途说明 |
|---|---|---|
| v3.1.13 | etcd_network_peer_sent_failures_total(补计数) |
peer 消息发送失败 |
| v3.1.14 | etcd_server_is_leader |
判断节点是否为 leader |
| v3.1.18 | etcd_server_version |
替代 Kubernetes 侧的 etcd-version-monitor |
| v3.1.19 | etcd_server_go_version |
运行二进制所用 Go 版本 |
| v3.1.19 | etcd_server_slow_read_indexes_total |
read-index 慢请求 |
| v3.1.19 | etcd_server_quota_backend_bytes |
当前配额大小 |
| v3.1.19 | etcd_mvcc_db_total_size_in_bytes、etcd_mvcc_db_total_size_in_use_in_bytes |
DB 物理分配尺寸 / 实际使用尺寸 |
| v3.1.20 | etcd_server_id、etcd_server_health_success、etcd_server_health_failures |
节点身份与健康检查结果 |
| v3.1.20 | etcd_server_read_indexes_failed_total |
read-index 失败 |
| v3.1.20 | etcd_snap_db_fsync_duration_seconds_count、etcd_snap_db_save_total_duration_seconds_bucket |
快照 fsync / 保存耗时 |
| v3.1.20 | etcd_network_snapshot_send_success/failures/total_duration_seconds、etcd_network_snapshot_receive_success/failures/total_duration_seconds |
快照发送/接收成功失败与耗时 |
其中三项指标的组合用法在 CHANGELOG 中有明确示范,值得原样保留为运维公式:
etcd_server_quota_backend_bytes 2.147483648e+09 # 当前配额大小(2 GB)
etcd_mvcc_db_total_size_in_bytes 20480 # 当前物理分配 DB 尺寸(20 KB)
etcd_mvcc_db_total_size_in_use_in_bytes 16384 # 完成 defrag 后的 DB 尺寸
可回收空间 = etcd_mvcc_db_total_size_in_bytes - etcd_mvcc_db_total_size_in_use_in_bytes
v3.1.20 还做了两项观测能力增强:
etcd_network_peer_round_trip_time_seconds从"只采样快照消息的 TCP 连接"改进为追踪 leader 心跳,样本更有代表性;- 启动时打印所有已注册的 gRPC 指标;并新增 gRPC 调试拦截器,启用
etcd --debug可查看逐请求的调试信息。
v3.1.21 则修复了 db_compaction_total_duration_milliseconds 指标恒测得 0 的 bug。
etcdctl 与 client v3:保活、锁与健康检查
endpoint health 输出修复(v3.1.21):此前 etcdctl endpoint health --write-out json 不可用(对应 issue #9532),v3.1.21 修复后统一了输出格式——无论何种错误类型,不可达端点的输出统一为 "<endpoint> is unhealthy: failed to commit proposal: <error message>"。当前仓库中集群不健康时 etcdctl 以退出码报错的分支见 ep_command.go(unhealthy cluster)。此外该版本还剔除了 discovery 时 DNS SRV 记录中的不安全端点。
租约 keepalive 节奏修复(v3.1.19):若 clientv3.Lease.KeepAlive 返回的 <-chan *clientv3LeaseKeepAliveResponse 从未被消费或队列已满,客户端曾以每 500ms 一次(而非预期的 TTL/3 间隔)发送 keepalive 请求,造成无谓的服务器压力;v3.1.19 修复了响应队列满时的 keepalive 间隔更新逻辑。当前仓库的 lease.go 仍保留了这一语义:KeepAlive 会尽最大努力永久续租,底层保活通道关闭或不可恢复错误时会返回 ErrKeepAliveHalted,提示"自动续租已损坏但 KeepAliveOnce 仍可用"。
并发包释放锁修复(v3.1.20):clientv3/concurrency 包在取消(cancelled)场景下会错误地释放锁 key,v3.1.20 修正了"取消时释放锁 key"的逻辑。
v3.1.11 的回移项:该版本回移了 "mvcc: sending events after restore"(issue #8411)与 coreos/bbolt v1.3.1-coreos.5(issue #8009),说明 3.1 分支在生命周期后期仍在接收主干修复,使用 3.1.x 生产集群时应尽量跟进高编号补丁版本。
升级与适用性提示
- CHANGELOG 在几乎每个版本都反复强调:升级前务必先读版本说明与 v3.1 upgrade guide(官方文档站),v3.1.0 相对 v3.0.0 存在破坏性变更(主要是 gRPC 指标弃用),v2→v3 用户应重点核对认证与 TLS 相关行为;
- 3.1.x 各版本编译 Go 版本为 Go 1.7.4~1.8.7,属于历史工具链信息;若当前仓库(主干分支)构建,应以仓库根目录 go.mod 声明的 Go 版本为准,二者不可混用;
- 本文引用的源码路径均基于当前仓库主干,用于印证 3.1 系列引入机制的现状;对已演进的特性(如
--max-snapshots移除、read-index 相关指标继续扩展),请以对应版本的 release tag 代码为准。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00