etcd 基于 Go 语言实现,因此,用户可以从github下载源代码自行编译,也可以下载编译好的二进制文件,甚至直接使用制作好的 Docker 镜像文件来体验。
介绍
- etcd 有 v2.x 和 v3.x 两大版本,且两个版本接口不一样,存储不同,数据相互隔离
二进制文件方式
参考
安装
编译好的二进制文件都在 github.com/coreos/etcd/releases
页面,用户可以选择需要的版本,或通过下载工具下载。
例如,使用 curl 工具下载压缩包,并解压。
$ curl -L https://github.com/coreos/etcd/releases/download/v3.2.10/etcd-v3.2.10-linux-amd64.tar.gz -o etcd-v3.2.10-linux-amd64.tar.gz
$ tar xzvf etcd-v3.2.10-linux-amd64.tar.gz
$ cd etcd-v3.2.10-linux-amd64
解压后,可以看到文件包括
$ ls
Documentation README-etcdctl.md README.md READMEv2-etcdctl.md etcd etcdctl
其中 etcd
是服务主文件,etcdctl
是提供给用户的命令客户端,其他文件是支持文档。
下面将 etcd
etcdctl
文件放到系统可执行目录(例如 /usr/local/bin/)。
$ sudo cp etcd* /usr/local/bin/
端口说明:
- 默认
2379
端口处理客户端的请求
2380
端口用于集群各成员间的通信
启动
启动 etcd 显示类似如下的信息:
# etcd
2017-12-03 11:18:34.406082 I | etcdmain: etcd Version: 3.2.10
2017-12-03 11:18:34.406226 I | etcdmain: Git SHA: GitNotFound
2017-12-03 11:18:34.406235 I | etcdmain: Go Version: go1.9.2
2017-12-03 11:18:34.406242 I | etcdmain: Go OS/Arch: darwin/amd64
2017-12-03 11:18:34.406250 I | etcdmain: setting maximum number of CPUs to 4, total number of available CPUs is 4
2017-12-03 11:18:34.406265 N | etcdmain: failed to detect default host (default host not supported on darwin_amd64)
2017-12-03 11:18:34.406279 W | etcdmain: no data-dir provided, using default data-dir ./default.etcd
2017-12-03 11:18:34.406457 N | etcdmain: the server is already initialized as member before, starting as etcd member...
2017-12-03 11:18:34.411579 I | embed: listening for peers on http://localhost:2380
2017-12-03 11:18:34.411938 I | embed: listening for client requests on localhost:2379
此时,可以使用 etcdctl
命令进行测试,设置和获取键值 testkey: "hello world"
,检查 etcd
服务是否启动成功:
# export ETCDCTL_API=3
$ etcdctl member list
8e9e05c52164694d, started, default, http://localhost:2380, http://localhost:2379
$ etcdctl put testkey "hello world"
OK
$ etcdctl get testkey
testkey
hello world
说明 etcd 服务已经成功启动了。
参数说明
常用配置的参数和它们的解释:
- –name:方便理解的节点名称,默认为 default,在集群中应该保持唯一,可以使用 hostname
- –data-dir:服务运行数据保存的路径,默认为 ${name}.etcd
- –snapshot-count:指定有多少事务(transaction)被提交时,触发截取快照保存到磁盘
- –heartbeat-interval:leader 多久发送一次心跳到 followers。默认值是 100ms
- –eletion-timeout:重新投票的超时时间,如果 follow 在该时间间隔没有收到心跳包,会触发重新投票,默认为 1000 ms
- –listen-peer-urls:和同伴通信的地址,比如 http://ip:2380,如果有多个,使用逗号分隔。需要所有节点都能够访问,所以不要使用 localhost!
- –listen-client-urls:对外提供服务的地址:比如 http://ip:2379,http://127.0.0.1:2379,客户端会连接到这里和 etcd 交互
- –advertise-client-urls:对外公告的该节点客户端监听地址,这个值会告诉集群中其他节点
- –initial-advertise-peer-urls:该节点同伴监听地址,这个值会告诉集群中其他节点
- –initial-cluster:集群中所有节点的信息,格式为 node1=http://ip1:2380,node2=http://ip2:2380,…。注意:这里的 node1 是节点的 –name 指定的名字;后面的 ip1:2380 是 –initial-advertise-peer-urls 指定的值
- –initial-cluster-state:新建集群的时候,这个值为 new;假如已经存在的集群,这个值为 existing
- –initial-cluster-token:创建集群的 token,这个值每个集群保持唯一。这样的话,如果你要重新创建集群,即使配置和之前一样,也会再次生成新的集群和节点 uuid;否则会导致多个集群之间的冲突,造成未知的错误
所有以 --init
开头的配置都是在 bootstrap
集群的时候才会用到,后续节点的重启会被忽略。
systemctl 启动
/etc/systemd/system/etcd.service
,参考
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
[Service]
Type=notify
Restart=always
RestartSec=5s
LimitNOFILE=40000
TimeoutStartSec=0
EnvironmentFile=-/etc/sysconfig/etcd-ssl
ExecStart=/usr/local/bin/etcd \
--name etcd1 \
--data-dir /data/bkee/public/etcd \
--initial-advertise-peer-urls http://<ip1>:2380 \
--listen-peer-urls http://<ip1>:2380 \
--advertise-client-urls http://<ip1>:2379 \
--listen-client-urls http://<ip1>:2379,http://127.0.0.1:2379 \
--initial-cluster etcd0=http://<ip0>:2380 \
--initial-cluster-state new \
--initial-cluster-token etcd-cluster-token \
--auto-compaction-retention 1
[Install]
WantedBy=multi-user.target
操作命令:
- systemctl enable etcd
- systemctl start etcd
Docker 镜像方式
- 可以通过下面的命令启动 etcd 服务监听到 2379 和 2380 端口,参考
- quay.io/coreos/etcd:v3.5.14
rm -rf /tmp/etcd-data.tmp && mkdir -p /tmp/etcd-data.tmp && \
docker rmi gcr.io/etcd-development/etcd:v3.5.14 || true && \
docker run \
-p 2379:2379 \
-p 2380:2380 \
--mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \
--name etcd-1 \
quay.io/coreos/etcd:v3.5.14 \
/usr/local/bin/etcd \
--data-dir /etcd-data \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://0.0.0.0:2379 \
--listen-peer-urls http://0.0.0.0:2380 \
--initial-advertise-peer-urls http://0.0.0.0:2380 \
--initial-cluster etcd-1=http://0.0.0.0:2380 \
--initial-cluster-token tkn \
--initial-cluster-state new \
--log-level info \
--logger zap \
--log-outputs stderr
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcd --version
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcdctl version
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcdutl version
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcdctl endpoint health
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcdctl put foo bar
docker exec etcd-gcr-v3.5.14 /usr/local/bin/etcdctl get foo
打开新的终端按照上一步的方法测试 etcd 是否成功启动。
docker-compose 方式
# Copyright Broadcom, Inc. All Rights Reserved.
# SPDX-License-Identifier: APACHE-2.0
version: '2'
services:
etcd1:
image: bitnami/etcd:3.5.14-debian-12-r0
# ports:
# - 2379
# - 2380
# - 23790
environment:
- ALLOW_NONE_AUTHENTICATION=yes
- ETCD_NAME=etcd1
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd1:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd1:2379
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
etcd2:
image: bitnami/etcd:3.5.14-debian-12-r0
environment:
- ALLOW_NONE_AUTHENTICATION=yes
- ETCD_NAME=etcd2
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd2:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd2:2379
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
etcd3:
image: bitnami/etcd:3.5.14-debian-12-r0
environment:
- ALLOW_NONE_AUTHENTICATION=yes
- ETCD_NAME=etcd3
- ETCD_INITIAL_ADVERTISE_PEER_URLS=http://etcd3:2380
- ETCD_LISTEN_PEER_URLS=http://0.0.0.0:2380
- ETCD_LISTEN_CLIENT_URLS=http://0.0.0.0:2379
- ETCD_ADVERTISE_CLIENT_URLS=http://etcd3:2379
- ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
- ETCD_INITIAL_CLUSTER=etcd1=http://etcd1:2380,etcd2=http://etcd2:2380,etcd3=http://etcd3:2380
- ETCD_INITIAL_CLUSTER_STATE=new
$ docker-compose up -d
[+] Running 4/4
✔ Network etcd_default Created 0.2s
✔ Container etcd-etcd2-1 Started 1.4s
✔ Container etcd-etcd3-1 Started 1.5s
✔ Container etcd-etcd1-1 Started
$ docker exec -it etcd-etcd1-1 bash
$ etcdctl version
etcdctl version: 3.5.14
API version: 3.5
$ etcdctl member list
ade526d28b1f92f7, started, etcd1, http://etcd1:2380, http://etcd1:2379, false
bd388e7810915853, started, etcd3, http://etcd3:2380, http://etcd3:2379, false
d282ac2ce600c1ce, started, etcd2, http://etcd2:2380, http://etcd2:2379, false
k8s 部署
参考
集群运行时重配置
- 使用如下命令管理集群节点
- 场景:机器升级、修改集群大小、替换故障机器、重启集群
- 集群大多数节点正常运行时才可操作
- 更新集群成员有两种情况
client URLs
用于客户端的 URL,即对外服务的 URL,通过 --advertise-client-urls
配置
peer URLs
用于监听 URL,即与其他节点通信
- 如果是移除 leader 的场景,新 leader 被选举时集群将处于
不活跃状态(inactive)
,且持续时间通常由选举超时时间和投票过程决定
- 若添加新成员到一个节点的集群时,在新成员启动前集群无法继续工作
etcdctl member add --initial-cluster-state existing --initial-cluster http://ip1:2380,http://ip2:2380
etcdctl member remove
etcdctl member update
etcdctl member list
调优
- 生成环境中,etcd 集群的性能受 CPU、内存、磁盘和网络的影响
- 若客户端达到数千个,每秒请求数可能在成千上万,建议使用 8~16 个 CPU 核
- 若具有上千个 watch 监视器或者数百万键值对的大型集群,建议内存 16GB 以上
- etcd 对磁盘写入延迟非常敏感,通常需要 7200 RPM 转速的磁盘,对于负载较重的集群,官方建议使用 SSD、NVME 固态磁盘
- 多个进程同时操作可能引起更高的 fsync 延迟
- SSD/NVME 相比机械盘,写入延迟较低、能够提高 etcd 的稳定性和可靠性
- 由于 etcd 的一致性复制已经获得了高可用,至少三个节点的集群不需要使用 RAID 的磁盘
- etcd 集群节点网络需要保证低延迟和高带宽,不可靠的网络将导致可用性低
- 避免多个数据中心部署 etcd 集群
- 网络延迟可能导致 Follower 成员与 Leader 之间通信的请求处理被延迟
- 通过提供 Leader 的网络优先级来提高 Follower 请求的响应,Linux 使用
tc
流控机制来确定对等流量的优先级
- 通过在输出端口建立一个队列来实现流量控制
- 若网络延迟高,etcd 集群各节点的心跳间隔和选举超时的设置需要优化
磁盘
- etcd 对磁盘 IO 比较敏感,建议采用 SSD 或 NVME 盘,可以使用
fio
测试磁盘读写性能
- WAL 日志受到磁盘 IO 写入速度影响
- fdatasync 延迟也会影响 etcd 性能
fio -filename=/dev/nvme1 -direct=1 -iodepth 1 -thread -rw=write -ioengine=psync -bs=4k -size=60G -numjobs=64 -runtime=10 -group_reporting -name=file
ionice -c2 -n0 -p $(pgrep etcd)
- etcd 默认空间配额大小为 2G,超过 2G 将不再写入数据,修改为 8G
--quota-backend-bytes 8589934592
网络
- 若 etcd leader 处理大量并发客户端请求,可能由于网络拥塞而延迟处理 follower 对等请求,follower 节点上可能出现如下的发送缓冲区错误的消息
dropped MsgProp to xxx since streamMsg's sending buffer is full
dropped MsgAppResp to xxx since streamMsg's sending buffer is full
- 使用 tc 调整对等流量进行优先级
- 集群各节点间通信的 2380 端口的命令优先级高于 2379 端口
- 依次执行过滤器,相同优先级时,系统按照命令的先后顺序执行
tc qdisc add dev eth0 root handle 1: prio bands 3
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip sport 2380 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 1 u32 match ip dport 2380 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip sport 2379 0xffff flowid 1:1
tc filter add dev eth0 parent 1: protocol ip prio 2 u32 match ip dport 2379 0xffff flowid 1:1
其他
- etcd 追加所有键值对的变更到日志中
- 每一行记录一个 key 的变更,日志规模在不断增加,为避免大量的日志,etcd 会定期生成快照
- 默认 10000 次变更才会保存快照,如果 etcd 的内存和磁盘使用率过高,可以降低该值
etcd --snapshot-count=5000 ...
ETCD_SNAPSHOT_COUNT=5000 etcd ...
- 时间参数
心跳间隔(etcd --heartbeat-interval=100 .../ETCD_HEARBEAT_INTERVAL=100 etcd ...)
:被设置为节点之间网络往返时间,etcd 默认心跳间隔是 100ms
- 推荐设置为节点之间的最大 RTT,一般可设置为平均 RTT 的 0.5~1.5 倍
- 过长的心态间隔也会延长选举超时时间
- RTT 一般使用 ping 命令检测
- 若网络性能不均,5s 是一个安全的 RTT 最高值
- 选举超时:默认是 1000ms
- k8s 中可以将 event 写到单独的 etcd 集群中
--etcd-servers="http://etcd1:2379,http://etcd2:2379,http://etcd3:2379" \
--etcd-servers-overrides="/events#http://etcd4:2379,http://etcd5:2379,http://etcd6:2379"
- etcd 多用于读多写少的场景,读写开销不一样
- 尽量避免频繁更新键值对数据
- 复用 lease,避免重复创建 lease
- 对于相同 TTL 失效时间的键值对,绑定到相同的 lease 租约上也可以避免大量重复创建 lease
F&Q
request sent was ignored by remote peer due to cluster ID mismatch
将 etcd 数据 /var/lib/etcd/
清理或备份,并重启服务