bigywater.tech
微服务 · 41

etcd lease:TTL、续约与 keepalive 通道

etcd 的租约 TTL 是怎么生效的?keepalive 要多频繁?一个 lease 挂很多 key 有什么好处?leader 切换时租约会怎样?这篇用单节点和三节点的 etcd 3.7.2 把它们量出来。

2.49 s
申请 TTL 1 s 时 etcd 实际给了 2 s,key 消失的中位数时间;TTL 5 s 的是 5.49 s(比 TTL 多约 0.5 s)
25.5 ms 对 10012 ms
一个 lease 挂 10000 个 key 的 revoke 用时,与 1000 个 lease 逐个 revoke 的总用时
18.7 s
TTL 10 s 的 lease 在 6 s 时杀掉 leader,key 实际消失的时刻(原定 10 s)

TTL 与到期

实测 · 本机执行输出
  申请的 TTL | etcd 回的 TTL | 最短     | 中位数    | 最长(key 消失用了多久,10 次)
  --------+-------------+--------+--------+--------------------
  1 s     | 2 s         | 2.06 s | 2.49 s | 2.52 s             
  2 s     | 2 s         | 2.48 s | 2.49 s | 2.52 s             
  3 s     | 3 s         | 3.47 s | 3.49 s | 3.51 s             
  5 s     | 5 s         | 5.47 s | 5.49 s | 5.52 s             
  etcd 对 TTL 有下限:申请 1 s 实际得到 2 s(我的理解是下限由选举超时推出来,这台默认选举超时 1 s,没有改参数验证);key 消失的时间比 TTL 多约半秒,看起来是 leader 周期性检查到期的 lease(检查周期约 0.5 s,这个周期是我从数据推测的,没有读源码)

etcd 对 TTL 有下限,key 在 TTL 之后再过约半秒才消失。

keepalive

实测 · 本机执行输出
  续约方式           | key       | 续约成功 / 发出 | 续约响应里的 TTL
  ---------------+-----------+-----------+-----------
  (a) 每 1.7 s 续约 | 一直存在      | 8 / 8     | 5         
  (b) 每 4.5 s 续约 | 一直存在      | 3 / 3     | 5         
  (c) 每 5.5 s 续约 | 5.4 s 时消失 | 0 / 2     | NULL      
  续约把剩余时间重置为完整的 TTL(响应里的 TTL 是 5);续约间隔小于 TTL 才能保住租约;lease 一旦过期,之后发出的 keepalive 就不再成功(上表 (c) 的两次续约响应里都没有大于 0 的 TTL),客户端必须重新申请 lease 并重新写 key

续约间隔小于 TTL 才能保住租约;过期之后要重新申请。

一个 lease 多个 key

实测 · 本机执行输出
  一个 lease 上挂的 key 数 | revoke 用时 | revoke 之后剩余的 key | 对照                     | 总用时     
  -------------------+-----------+------------------+------------------------+---------
  100                | 12.2 ms   | 0                | 100 个 lease 逐个 revoke  | 1069 ms 
  1000               | 14.0 ms   | 0                | 1000 个 lease 逐个 revoke | 10012 ms
  10000              | 25.5 ms   | 0                | 1000 个 lease 逐个 revoke | 9518 ms 
  revoke 一次请求就把挂在这个 lease 上的所有 key 删光(之后查询剩余为 0),用时随 key 数增长得很慢;而每个 key 一个 lease 时,要发 N 次 revoke,每次约 10 ms。服务发现里,一个服务实例通常只有一个 key,一个 lease;一个进程注册多个 key(例如多个服务名、多个端口)时,共用一个 lease 比较省

revoke 一次删光所有挂着的 key,比每个 key 一个 lease 省得多。

leader 切换

实测 · 本机执行输出
  杀 leader 的时刻(申请后) | 杀之前 timetolive 的剩余 | 新 leader 选出的时刻 | 新 leader 上 timetolive 的剩余 | key 实际消失的时刻(申请后)
  ------------------+--------------------+----------------+---------------------------+-----------------
  6.0 s             | 3                  | 7.5 s          | 10                        | 18.7 s          
  原本申请后 10 s 到期;leader 切换之后,新 leader 上 timetolive 回报的剩余时间是完整的 10 s(杀 leader 之前是 3 s),key 因此比原定的到期时间晚得多才消失。我的理解是 lease 的剩余时间只在 leader 的内存里按时钟走,换 leader 之后新 leader 把它们重置为完整的 TTL(这个机制我没有读源码验证,只看到了结果)

新 leader 把 lease 剩余时间重置为完整的 TTL。

分步演示

etcd lease
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8 / Go / nginx / Envoy / etcd / Consul / Nacos / OpenTelemetry / Prometheus(按各篇注明用到哪些及版本);所有服务都是本机自己起的进程,端口 9150 以上,只监听 127.0.0.1,不连任何外部服务,不碰本机已有的实例;故障用 kill -9 进程、让连接断开或在代码里注入延迟与错误来制造;计时用 time.perf_counter,数字每次运行会有小幅抖动。etcd 3.7.2(Homebrew),单节点和 3 节点都是自己起的进程,通过 HTTP/JSON 网关 /v3/lease/*、/v3/kv/* 操作(etcdt.py);“key 消失”是用 serializable 读每 20 ms 轮询得到的;关于 TTL 下限、检查周期、leader 切换后重置剩余时间的机制是我根据数据做的解释,没有读 etcd 源码;每种配置的次数见各节
    • 没有验证:lease checkpoint 功能(checkpoint-interval)对 leader 切换后剩余时间的影响;--experimental-enable-lease-checkpoint;etcd 集群更大时的 lease 开销;etcd 客户端库(clientv3)的 KeepAlive 流与重试;网络分区时 lease 的行为
    京ICP备2026067502号-1京公网安备11010502063487号