性能

理解性能:延迟与吞吐量

了解性能

etcd 提供了稳定且持续的高性能。性能由两个因素定义:延迟和吞吐量。延迟是完成一个操作所需的时间。吞吐量是在某个时间段内完成的操作总数。通常,当 etcd 接受并发客户端请求时,平均延迟会随着整体吞吐量的增加而增加。在常见的云环境中,例如 Google Compute Engine (GCE) 上的标准 n-4 或 AWS 上的类似机器类型,一个三节点的 etcd 集群在轻负载下可以在不到一毫秒的时间内完成一个请求,并且在重负载下每秒可以完成超过 30,000 个请求。

etcd 使用 Raft 共识算法在成员之间复制请求并达成一致。共识性能,特别是提交延迟,受到两个物理限制:网络 IO 延迟和磁盘 IO 延迟。完成一个 etcd 请求所需的最短时间是成员之间的网络往返时间 (RTT),加上 fdatasync 将数据提交到永久存储所需的时间。数据中心内的 RTT 可能长达几百微秒。在美国境内的典型 RTT 大约是 50 毫秒,在洲际之间可能会慢至 400 毫秒。传统硬盘的典型 fdatasync 延迟约为 10 毫秒。对于 SSD,延迟通常低于 1 毫秒。为了提高吞吐量,etcd 会将多个请求批量处理并提交给 Raft。这种批量处理策略使 etcd 在重负载下仍能保持高吞吐量。

还有其他子系统会影响 etcd 的整体性能。每个序列化的 etcd 请求必须通过 etcd 的基于 boltdb 的 MVCC 存储引擎运行,这通常需要几十微秒才能完成。定期地,etcd 会对其最近应用的请求进行增量快照,并将其与之前的磁盘快照合并。这一过程可能导致延迟峰值。虽然在 SSD 上通常不是问题,但在 HDD 上可能会使观察到的延迟翻倍。同样,正在进行的压缩也会影响 etcd 的性能。幸运的是,由于压缩是交错进行的,因此不会与常规请求竞争资源,其影响通常是微不足道的。RPC 系统 gRPC 为 etcd 提供了一个明确定义且可扩展的 API,但它也会引入额外的延迟,尤其是在本地读取时。

基准测试

可以使用随 etcd 附带的 benchmark CLI 工具来测试 etcd 的性能。

为了提供一些基准性能数据,我们考虑一个三节点的 etcd 集群,其硬件配置如下:

  • Google Cloud Compute Engine
  • 3 台 8 vCPU + 16GB 内存 + 50GB SSD 的机器
  • 1 台 16 vCPU + 30GB 内存 + 50GB SSD 的机器(客户端)
  • Ubuntu 17.04
  • etcd 3.2.0, go 1.8.3

在这种配置下,etcd 大约可以写入:

键的数量键的大小(字节)值的大小(字节)连接数客户端数量目标 etcd 服务器平均写入 QPS每个请求的平均延迟平均服务器 RSS
10,000825611仅领导者5831.6 毫秒48 MB
100,00082561001000仅领导者44,34122 毫秒124MB
100,00082561001000所有成员50,10420 毫秒126MB

示例命令包括:

# write to leader
benchmark --endpoints=${HOST_1} --target-leader --conns=1 --clients=1 \
    put --key-size=8 --sequential-keys --total=10000 --val-size=256
benchmark --endpoints=${HOST_1} --target-leader  --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

# write to all members
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

线性化读取请求通过集群成员的多数派达成共识,以获取最新的数据。可序列化读取请求比线性化读取更便宜,因为它们由任何一个单个 etcd 成员提供服务,而不是由成员的多数派提供服务,但可能会提供陈旧的数据。etcd 可以读取:

请求数量键的大小(字节)值的大小(字节)连接数客户端数量一致性平均读取 QPS每个请求的平均延迟
10,000825611线性化1,3530.7 毫秒
10,000825611可序列化2,9090.3 毫秒
100,00082561001000线性化141,5785.5 毫秒
100,00082561001000可序列化185,7582.2 毫秒

示例命令包括:

# Single connection read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
    range YOUR_KEY --consistency=l --total=10000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=1 --clients=1 \
    range YOUR_KEY --consistency=s --total=10000

# Many concurrent read requests
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    range YOUR_KEY --consistency=l --total=100000
benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    range YOUR_KEY --consistency=s --total=100000

我们建议在新环境中首次设置 etcd 集群时运行基准测试,以确保集群达到足够的性能;集群的延迟和吞吐量可能对环境的细微差异非常敏感。


最后更新于 2025 年 6 月 3 日:递归地将 v3.6 的内容复制到 v3.7(a90b2a6)