土法炼钢 · 系统与基础设施

【etcd】Txn 与并发语义:compare/mod 与 Jepsen 边界

文章导航

分类入口
distributedkubernetes
标签入口
#etcd#txn#compare#mvcc#jepsen#concurrency#v3.5.33

目录

第 7 篇 讲过 Put 与 quota;第 10 篇 说明 KeepAlive 不经 Raft。协调层里 CAS、选举、锁 几乎都写成 Txn。误区是把「用了 Txn」等同于「可串行化协调原语」——Jepsen 对 etcd 的证伪边界要分开看:多 key KV Txn 与 compare/mod 路径 vs Lease 会话锁

本篇钉 TxnRequest 在 v3.5.33 的实现:applyCompares、嵌套 Txn、isTxnReadonly 的 ReadIndex 短路,以及 Jepsen etcd 3.4.3distributed/53 的分工。不写未跑并发测试数字。

本篇在系列中的位置

篇目 核心内容
第 10 篇 · Lease 与 KeepAlive TTL、checkpoint、Leader 切换
第 11 篇 · Txn 与并发语义 compare/mod、Jepsen 边界
第 12 篇 · Compaction 与容量 auto-compaction、quota、alarm
系列目录 五轴、阅读路径

版本锚定:etcd v3.5.33(tag v3.5.33)。对齐 server/etcdserver/apply.goTxnapplyCompare)、server/etcdserver/v3_server.goTxn 入口)@ etcd-io/etcd v3.5.33。Jepsen 结论引用 etcd 3.4.3 报告(B 级边界,非 3.5.33 逐条复现)。无 Jepsen 重跑则不粘贴操作历史或 checker 输出。


一、Txn 在 API 层的两条路径

客户端 TxnCompare(谓词)与 Success/FailureRequestOp 列表,可嵌套 Txn)。

EtcdServer.Txnv3_server.go)分叉:

类型 判定 路径
只读 Txn Success/Failure 仅含 RequestRange 默认 linearizableReadNotifydoSerializeapplyV3Base.Txn 不经 propose
Serializable 只读 所有 Range 带 Serializable: true 跳过 ReadIndex
写 Txn 含 Put/DeleteRange/嵌套写 raftRequest(Txn) → 单条 Raft entry → apply

写 Txn 与 Put 共享 单 Raft 组单写者 槽位(第 2、6 篇);compare 失败时仍占一条 log entry(mod 为空),revision 可能 不变 或仅 bump header——以 applyTxn 是否产生 changes 为准。


二、compare:MOD、CREATE、VERSION 与空 key

compareToPath 先对 rt.Compare 调用 applyCompares;全真走 Success 分支,否则 Failure。嵌套 Txn 递归展开 txnPath []bool

applyCompareapply.go)对每个 Compare:

  1. Range(key, rangeEnd)当前 ReadView revision 的 KV;
  2. 无 KV 时:Compare_VALUE 恒 false;其他 target 与 零值 KV 比较;
  3. 有 KV 时:对 range 内 每个 KV 调用 compareKV,全满足才 true。

compareKV 支持的 Target

Target 比较字段 典型用途
VALUE bytes.Compare(value) 值 CAS
CREATE CreateRevision key 是否存在 / 创建世代
MOD ModRevision 乐观锁、fencing(ModRevision 作 token)
VERSION Version 逻辑写次数
LEASE Lease 绑定租约 ID

Result 支持 =, !=, >, <Compare_EQUAL 等)。clientv3If(Compare(...)) 是同一 protobuf 的封装。

fencing 惯用法distributed/51):锁 Txn 成功后取 Header.Revision 或 key 的 ModRevision 作 token;写资源时 Compare(ModRevision("<resource>"), "<", token),拒绝 stale holder 的写入——这是 应用层协议,不是 etcd 自动提供 lock 语义。


三、applyTxn 与 MVCC 可见性

applierV3backend.Txn 流程:

  1. 只读阶段:Read(ConcurrentReadTxMode) 或实验性 SharedBufReadTxMode 上执行 compare + checkRequests(预检查 range 权限与 revision);
  2. 若写 Txn:txn.End()KV().Write() 开启真实写事务——注释强调写 serialized on raft loop,ReadView revision 即本次写 txn revision;
  3. applyTxn 执行 Success/Failure 分支中的 Put/Delete/Range;
  4. 写失败 panicunexpected error during txn with writes),只读失败仅 log——体现 写 Txn 不可部分成功 的不变量。

Txn 内 Range 读到的是 apply 时刻 MVCC 快照;与 Percolator 两阶段不同,etcd 无跨 key 锁表,靠 Raft 日志全序 + 单 store 写者保证 原子 apply

嵌套 Txn 的 compare 按路径逐段求值;深度过大时成本线性于 compare 次数 × range 宽度(源码 TODO 提到 range 分块优化)。


四、Jepsen 边界:什么被证伪、什么没有

distributed/53 · Jepsen 方法论 第 5.5 节与 Raft 深度重写 均引用 Jepsen etcd 3.4.3(2019–2020 报告链):

子系统 Jepsen 结论(3.4.3) 工程含义
KV 读/写、多 key Txn Knossos 等检查器下 strict-serializable(默认线性一致读路径) compare/mod 协调 在 KV 模型内 与 Raft 一致
--serializable 允许 stale 与文档一致;不可用于锁验证
Lease 锁 / 会话 不安全 子集(clock、partition 组合) concurrency.Mutexfencing + 业务校验
corrupt-check × Watch 特定配置竞态(3.4.3) 3.5.x 修复链;生产慎开实验 flag

版本边界:Jepsen 钉 3.4.3,本篇机制钉 3.5.33——不能把 3.4.3 的 bug 列表原样当作 3.5.33 未修,也不能假设 3.5.33 已独立重跑 Jepsen。合理写法是:KV Txn 路径的设计目标仍是 linearizable + Raft 全序;Lease 轴另列。

TiKV Percolatortikv-htap)对照:etcd Txn 是 单 Raft 组上的轻量 CAS 批,无分布式锁服务、无 GC 事务 record——选型见第 16 篇。


五、并发语义速查表

场景 推荐机制 避免
选主 / 抢锁 Txn + CREATE=0 或 MOD 比较 + Lease 无 Lease 的永久 key
保护共享资源写 MOD revision fencing 只 Compare VALUE
读最新配置 线性一致 Get 或写 Txn 只读 Serializable 默认误用
批量条件更新 单 Txn 多 Put 客户端多次 Put 无 compare
Leader 租约 Lease + KeepAlive 把 KeepAlive 当 Txn

开放争论:strict-serializable 来自 黑盒历史检验,不覆盖 所有 client 库用法(例如本地缓存 revision、错误重试序);DST 路径见 distributed/54,与 Jepsen 互补(53 篇表格)。


六、谱系与开放问题

Lamport:线性一致(1979)→ Herlihy & Wing 形式化(1990)
  → Jepsen:历史检验 strict-serializable(Kingsbury)
  → etcd:Raft 全序 + MVCC apply → KV Txn 通过 3.4.3 检验
  → Lease 锁:会话 + 时钟 → 不在同一检验子集
  → 开放:K8s 全链路(apiserver + watch cache)无统一 Jepsen 模型

本篇不写什么:client/v3 concurrency 包逐函数走读;Jepsen Clojure 源码;未重跑的 3.5.33 Jepsen 数字。


参考资料

规范 / 官方文档 / 源码(A)

论文 / 测试报告(A/B)

站内对照


上一篇Lease 与 KeepAlive

下一篇Compaction、Defrag 与容量

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .