«

etcd 性能评测

参照官方的性能评测方法,在自己的机器上做相应的评测

搭建 etcd 集群

考虑线上场景和简易型,直接通过容器来搭建官方的 etcd 集群,脚本如下:

# 对于每台机器
docker ps -a | grep etcd | grep -v k8s  
docker rm -f etcd

ETCD_VERSION=v3.1.9  
TOKEN=my-etcd-token  
CLUSTER_STATE=new  
NAME_1=etcd-node-0  
NAME_2=etcd-node-1  
NAME_3=etcd-node-2  
HOST_1=10.120.173.120  
HOST_2=10.120.172.113  
HOST_3=10.120.173.83  
CLUSTER=${NAME_1}=http://${HOST_1}:23801,${NAME_2}=http://${HOST_2}:23801,${NAME_3}=http://${HOST_3}:23801

# 对于节点1
THIS_NAME=${NAME_1}  
THIS_IP=${HOST_1}  
sudo docker run -d --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \  
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:23801 --listen-peer-urls http://${THIS_IP}:23801 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker logs -f etcd

# 对于节点2
THIS_NAME=${NAME_2}  
THIS_IP=${HOST_2}  
sudo docker run -d --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \  
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:23801 --listen-peer-urls http://${THIS_IP}:23801 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker logs -f etcd

# 对于节点3
THIS_NAME=${NAME_3}  
THIS_IP=${HOST_3}  
sudo docker run -d --net=host --name etcd quay.io/coreos/etcd:${ETCD_VERSION} \  
    /usr/local/bin/etcd \
    --data-dir=data.etcd --name ${THIS_NAME} \
    --initial-advertise-peer-urls http://${THIS_IP}:23801 --listen-peer-urls http://${THIS_IP}:23801 \
    --advertise-client-urls http://${THIS_IP}:2379 --listen-client-urls http://${THIS_IP}:2379 \
    --initial-cluster ${CLUSTER} \
    --initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
docker logs -f etcd

镜像拉取需要配置代理,或者通过scp拷贝过去

理解性能

决定 etcd 性能的关键因素,包括:

etcd 使用 Raft 一致性算法来在成员之间复制请求并达成一致。

一致性性能,特别是提交延迟,受限于两个物理约束:

完成一个 etcd 请求的最小时间是成员之间的网络往返时延(Round Trip Time / RTT),加需要提交数据到持久化存储的 fdatasync 时间。

机械硬盘的典型 fdatasync 延迟是大概 10ms。对于 SSD 硬盘, 延迟通常低于 1ms。

为了提高吞吐量, etcd 将多个请求打包在一起并提交给 Raft。

有其他子系统影响到 etcd 的整体性能。

etcd 定期递增快照它最近实施的请求,将他们和之前在磁盘上的快照合并。这个过程可能导致延迟尖峰(latency spike)。

进行中的压缩可以影响 etcd 的性能。

RPC 系统,gRPC,为 etcd 提供定义良好,可扩展的 API。

评测性能

可以通过 etcd 自带的 benchmark CLI 工具来评测 etcd 的性能.

对于某些基线性能数字,考虑搭建3节点 etcd 集群,带有下列硬件配置:

对应的机器列表如下:

| 机器名 | IP | |----------------|-------------------| | HOST1 | 10.120.173.1 | | HOST2 | 10.120.173.2 | | HOST_3 | 10.120.173.3 | | CLIENT | 10.120.173.4 |

使用这些配置,采样命令如下:

HOST_1=http://10.120.173.1:2379  
HOST_2=http://10.120.173.2:2379  
HOST_3=http://10.120.173.3:2379

# 假定 HOST_1 是 leader, 写入请求发到 leader,连接数1,客户端数1
./benchmark --endpoints=${HOST_1} --conns=1 --clients=1 \
    put --key-size=8 --sequential-keys --total=10000 --val-size=256

# 假定 HOST_1 是 leader, 写入请求发到 leader,连接数100,客户端数1000
./benchmark --endpoints=${HOST_1} --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

# 写入发到所有成员,连接数100,客户端数1000
./benchmark --endpoints=${HOST_1},${HOST_2},${HOST_3} --conns=100 --clients=1000 \
    put --key-size=8 --sequential-keys --total=100000 --val-size=256

etcd 近似的写入指标如下:

| key的数量 | Key的大小 | Value的大小 | 连接数量 | 客户端数量 | 目标 etcd 服务器 | 平均写入 QPS | 每请求平均延迟 | 内存 | |----------------|-------------------|---------------------|-----------------------|-------------------|--------------------|-------------------|-----------------------------|--------| | 10,000 | 8 | 256 | 1 | 1 | 只有主 | 126 | 7.7ms | | | 100,000 | 8 | 256 | 100 | 1000 | 只有主 | 16,033 | 60ms | | | 100,000 | 8 | 256 | 100 | 1000 | 所有成员 | 15,102 | 63ms | |

注:key和value的大小单位是 字节 / bytes

为了一致性,线性化(Linearizable)读取请求要通过集群成员的法定人数来获取最新的数据。串行化(Serializable)读取请求比线性化读取要廉价一些,因为他们是通过任意单台 etcd 服务器来提供服务,而不是成员的法定人数,代价是可能提供过期数据。

采样命令如下:

HOST_1=http://10.120.173.1:2379  
HOST_2=http://10.120.173.2:2379  
HOST_3=http://10.120.173.3:2379

# Linearizable 读取请求
./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=100 --clients=1000 \
    range YOUR_KEY --consistency=l --total=100000

# Serializable 读取请求,使用每个成员然后将数字加起来
for endpoint in ${HOST_1} ${HOST_2} ${HOST_3}; do  
    ./benchmark --endpoints=$endpoint --conns=1 --clients=1 \
        range YOUR_KEY --consistency=s --total=10000
done  
for endpoint in ${HOST_1} ${HOST_2} ${HOST_3}; do  
    ./benchmark --endpoints=$endpoint --conns=100 --clients=1000 \
        range YOUR_KEY --consistency=s --total=100000
done  

etcd 近似读取指标如下:

| 请求数量 | Key 大小 | Value 大小 | 连接数量 | 客户端数量 | 一致性 | 每请求平均延迟 | 平均读取 QPS | |--------------------|-------------------|---------------------|-----------------------|-------------------|-------------|-----------------------------|------------------| | 10,000 | 8 | 256 | 1 | 1 | 线性化 | 1.2ms | 824 | | 10,000 | 8 | 256 | 1 | 1 | 串行化 | 0.6ms | 1,628 | | 100,000 | 8 | 256 | 100 | 1000 | 线性化 | 23.8ms | 37,679 | | 100,000 | 8 | 256 | 100 | 1000 | 串行化 | 43.5ms | 22,458 |

分析

读取指标的时候,按理说串行化要比线性化要好

影响性能的因素:磁盘(是否SSD),CPU(很多其他应用),内存(这个相对比较充足)

分享