etcd
用于分布式系统的最重要数据的分布式的、可靠的键值存储。
提示:
- 在阅读本文之前,建议先阅读 raft 算法
ectd 是强一致的、分布式的键值存储,它提供一种可靠的方式,来存储分布式系统或机器集群需要访问的数据。它在网络分区期间优雅地处理 Leader 选举,并且可以容忍机器故障,即使是在 Leader 节点中。
使用标准的 HTTP 工具,比如 curl,读写值。
与标准文件系统一样,在层次结构组织的目录中,存储数据。
监听特定键或目录的变化,对值的变化做出反应。
关于从预构建二进制文件(pre-built binaries)或源码安装 etcd 的细节,请参阅官方文档。接下来讲述如何安装预构建二进制文件。
安装 etcd 的最简单方式是从预构建二进制文件:
解压归档文件。这将生成包含二进制文件的目录
将可执行的二进制文件添加到 PATH 中。比如,将二进制文件重命名和/或移动到 PATH 的某个目录中(比如 /usr/local/bin),或将前一步创建的目录添加到 PATH 中
在 Shell 中测试,etcd 在 PATH 中:
$ etcd --versionetcd Version: 3.5.0...官网教程:https://etcd.io/docs/v3.5/tutorials/how-to-setup-cluster/
在 etcd 中设置集群指南

在每个 etcd 节点上,指定集群成员:
CLUSTER_STATE=newNAME_1=machine-1NAME_2=machine-2NAME_3=machine-3HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_3=192.168.56.123CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380在每台机器上运行:
# 在第一台机器上运行THIS_NAME=${NAME_1}THIS_IP=${HOST_1}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \ --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}
# 在第二台机器上运行THIS_NAME=${NAME_2}THIS_IP=${HOST_2}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \ --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}
# 在第三台机器上运行THIS_NAME=${NAME_3}THIS_IP=${HOST_3}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 --listen-peer-urls http://${THIS_IP}:2380 \ --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}现在 etcd 集群已经就绪,使用 etcdctl 连接 etcd:
x
export ETCDCTL_API=3HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_3=192.168.56.123ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
etcdctl --endpoints=$ENDPOINTS member listetcd 集群访问指南

put 命令用于写:
etcdctl --endpoints=$ENDPOINTS put foo "Hello World!"get 用于从 etcd 读:
etcdctl --endpoints=$ENDPOINTS get fooetcdctl --endpoints=$ENDPOINTS --write-out="json" get foo根据前缀提取 etcd 键的指南

etcdctl --endpoints=$ENDPOINTS put web1 value1etcdctl --endpoints=$ENDPOINTS put web2 value2etcdctl --endpoints=$ENDPOINTS put web3 value3
etcdctl --endpoints=$ENDPOINTS get web --prefix描述删除 etcd 键的方式

etcdctl --endpoints=$ENDPOINTS put key myvalueetcdctl --endpoints=$ENDPOINTS del key
etcdctl --endpoints=$ENDPOINTS put k1 value1etcdctl --endpoints=$ENDPOINTS put k2 value2etcdctl --endpoints=$ENDPOINTS del k --prefix进行事务性写入的指南
txn 将多个请求包装进单个事务:

xxxxxxxxxxetcdctl --endpoints=$ENDPOINTS put user1 badetcdctl --endpoints=$ENDPOINTS txn --interactive
compares:value("user1") = "bad"
success requests (get, put, delete):del user1
failure requests (get, put, delete):put user1 good监视 etcd 键的指南
watch 用于获取未来变更的通知:

etcdctl --endpoints=$ENDPOINTS watch stock1etcdctl --endpoints=$ENDPOINTS put stock1 1000
etcdctl --endpoints=$ENDPOINTS watch stock --prefixetcdctl --endpoints=$ENDPOINTS put stock1 10etcdctl --endpoints=$ENDPOINTS put stock2 20在 etcd 中创建租约(lease)的指南
lease 用于带 TTL 的写:

xxxxxxxxxxetcdctl --endpoints=$ENDPOINTS lease grant 300# lease 2be7547fbc6a5afa granted with TTL(300s)
etcdctl --endpoints=$ENDPOINTS put sample value --lease=2be7547fbc6a5afaetcdctl --endpoints=$ENDPOINTS get sample
etcdctl --endpoints=$ENDPOINTS lease keep-alive 2be7547fbc6a5afaetcdctl --endpoints=$ENDPOINTS lease revoke 2be7547fbc6a5afa# or after 300 secondsetcdctl --endpoints=$ENDPOINTS get sample在 etcd 中创建分布式锁的指南
lock 用于分布式锁:

etcdctl --endpoints=$ENDPOINTS lock mutex1
# another client with the same name blocksetcdctl --endpoints=$ENDPOINTS lock mutex1在 etcd 集群中,实施主节点选举的指南
elect 用于主节点选举:

xxxxxxxxxxetcdctl --endpoints=$ENDPOINTS elect one p1
# another client with the same name blocksetcdctl --endpoints=$ENDPOINTS elect one p2检查 etcd 集群状态的指南
为每台机器指定初始集群配置:
xxxxxxxxxxetcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status
+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+| 10.240.0.17:2379 | 4917a7ab173fabe7 | 3.5.0 | 45 kB | true | false | 4 | 16726 | 16726 | || 10.240.0.18:2379 | 59796ba9cd1bcd72 | 3.5.0 | 45 kB | false | false | 4 | 16726 | 16726 | || 10.240.0.19:2379 | 94df724b66343e6c | 3.5.0 | 45 kB | false | false | 4 | 16726 | 16726 | |+------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------|etcdctl --endpoints=$ENDPOINTS endpoint health
10.240.0.17:2379 is healthy: successfully committed proposal: took = 3.345431ms10.240.0.19:2379 is healthy: successfully committed proposal: took = 3.767967ms10.240.0.18:2379 is healthy: successfully committed proposal: took = 4.025451ms关于 etcd 数据库快照的指南
snapshot 用于保存 etcd 数据库的时间点(point-in-time)快照:

快照只能从一个 etcd 节点请求,因此 --endpoints 标志应该只包含一个端点。
ENDPOINTS=$HOST_1:2379etcdctl --endpoints=$ENDPOINTS snapshot save my.db
Snapshot saved at my.dbxxxxxxxxxxetcdctl --write-out=table --endpoints=$ENDPOINTS snapshot status my.db
+---------+----------+------------+------------+| HASH | REVISION | TOTAL KEYS | TOTAL SIZE |+---------+----------+------------+------------+| c55e8b8 | 9 | 13 | 25 kB |+---------+----------+------------+------------+处理 etcd 集群成员的指南
memeber 用于添加、移除、更新成员:

在每台机器上执行:
x
# For each machineTOKEN=my-etcd-token-1CLUSTER_STATE=newNAME_1=etcd-node-1NAME_2=etcd-node-2NAME_3=etcd-node-3HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_3=192.168.56.123CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380在 node 1 上执行:
x
THIS_NAME=${NAME_1}THIS_IP=${HOST_1}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 \ --listen-peer-urls http://${THIS_IP}:2380 \ --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}在 node 2 上执行:
xxxxxxxxxxTHIS_NAME=${NAME_2}THIS_IP=${HOST_2}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 \ --listen-peer-urls http://${THIS_IP}:2380 \ --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}在 node3 上执行:
x
THIS_NAME=${NAME_3}THIS_IP=${HOST_3}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 \ --listen-peer-urls http://${THIS_IP}:2380 \ --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}然后使用 member remove 和 member add 命令替换成员:
x
# 获取 member IDexport ETCDCTL_API=3HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_3=192.168.56.123etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 member list
# 移除成员MEMBER_ID=300774bba1f38564etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379,${HOST_3}:2379 \ member remove ${MEMBER_ID}
# 添加新成员 node 4export ETCDCTL_API=3NAME_1=etcd-node-1NAME_2=etcd-node-2NAME_4=etcd-node-4HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_4=192.168.56.124 # 新成员etcdctl --endpoints=${HOST_1}:2379,${HOST_2}:2379 \ member add ${NAME_4} \ --peer-urls=http://${HOST_4}:2380下面,使用 --initial-cluster-state existing 标记启动新成员:
xxxxxxxxxx# [警告]如果从相同的磁盘空间启动新成员,# 确保移除旧成员的数据目录## 使用 “existing” 标记重启
TOKEN=my-etcd-token-1CLUSTER_STATE=existingNAME_1=etcd-node-1NAME_2=etcd-node-2NAME_4=etcd-node-4HOST_1=192.168.56.121HOST_2=192.168.56.122HOST_4=192.168.56.124 # 新成员CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_4}=http://${HOST_4}:2380
THIS_NAME=${NAME_4}THIS_IP=${HOST_4}etcd --data-dir=data.etcd --name ${THIS_NAME} \ --initial-advertise-peer-urls http://${THIS_IP}:2380 \ --listen-peer-urls http://${THIS_IP}:2380 \ --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}