在Linux部署Etcd集群

发布时间 2023-04-05 16:39:18作者: 我有八千部下

前言

目前解决分布式系统下数据强一致性的主要算法理论是Paxos和Raft,偏向CAP定理一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)中的CP。

Raft在容错和性能方面和Paxos相当,不同之处在于它将问题分解成相对独立的子问题,逻辑较为清晰,更易于理解。关于Raft 详细介绍参考 GitHub - raft

Etcd是遵循Raft算法理论开发出来的高一致性分布式存储,功能和遵循Paxos简化版ZAB(Zookeeper Atomic Broadcast)协议开发出来的Zookeeper差不多。

Etcd用是键(Key)值(Value)存储,类似文档的存储结构,支持SSL认证(ZK不支持),基准测试为 10,000 次写入/秒。

可以用来做服务注册与发现、消息发布与订阅、负载均衡、分布式通知与协调、分布式锁、leader 选举等。

如果文章有帮助,可以随手关注、点赞、转发下,一起学习进步,祝大家顺利。

安装步骤

我们在这里计划使用3台服务器node1(172.20.0.2)、node2(172.20.0.3)、node3(172.20.0.4)部署3个Etcd节点。

文内很多配置使用了域名(node1、node2、node3)来代替IP地址,这个需要提前在/etc/hosts下配置并使其生效。比如:

echo '追加host配置' > /dev/null
echo '
172.20.0.2 node1
172.20.0.3 node2
172.20.0.4 node3' >> /etc/hosts

echo '使host配置生效' > /dev/null
/etc/init.d/network restart

Etcd需要用到接收客户端请求端口2379和节点间通信端口2380,需要配置安全组规则或者防火墙来保证端口畅通。

安装

用YUM安装Etcd。

echo '安装' > /dev/null
yum install etcd -y

查看Etcd命令行客户端etcdctl的帮助信息会看到一行警告(WARNING),意思是系统环境变量没有指定etcdctl的应用程序接口(Application Programming Interface, API)版本,现在默认使用的是v2版。

etcdctl -h

image-20211211145848266

我们追加环境变量来指定使用v3版的API。两个版本的API使用方式有很多区别,如果更喜欢v2可以不改,或者将环境变量设置成2,文章后面的脚本就需要修改成v2的。

echo '追加环境变量' > /dev/null
echo '
export ETCDCTL_API=3' >> /etc/profile

echo '使环境变量生效' > /dev/null
source /etc/profile

echo '查看版本' > /dev/null
etcdctl version

image-20211211150749534

etcdctl可以在任意Etcd节点使用,通过命令行可以查看简单帮助(etcdctl -h)。建议参考 GitHub - etcdctl,非常详细,可以直接看到演示效果。

配置

Etcd配置文件完整路径是/etc/etcd/etcd.conf,这里只使用了必要的配置参数,所有配置项的详细信息参考 Etcd - 配置

不同节点需要改这些配置项ETCD_NAME、ETCD_DATA_DIR、ETCD_LISTEN_PEER_URLS、ETCD_LISTEN_CLIENT_URLS、ETCD_INITIAL_ADVERTISE_PEER_URLS、ETCD_ADVERTISE_CLIENT_URLS

echo '备份配置' > /dev/null
cp /etc/etcd/etcd.conf /etc/etcd/etcd.conf.bak

echo '覆盖配置文件中的内容' > /dev/null
echo '#[Member]
# 当前etcd名字,可以自定义
ETCD_NAME="node1"
# 数据文件目录,可以自定义,这里是根据[ETCD_NAME].etcd
ETCD_DATA_DIR="/var/lib/etcd/node1.etcd"
# 用于监听其他etcd消息的当前etcd地址列表,多个IP或端口号不同的地址用逗号分隔。IP指定为0.0.0.0相当于监听所有网卡接口的同一个端口,IP不能是域名
ETCD_LISTEN_PEER_URLS="http://172.20.0.2:2380"
# 用于监听客户端消息的当前etcd地址表,和ETCD_LISTEN_PEER_URLS要求一致
ETCD_LISTEN_CLIENT_URLS="http://localhost:2379,http://172.20.0.2:2379"

#[Clustering]
# 告诉其他etcd,当前etcd通信的地址列表,也就是ETCD_LISTEN_PEER_URLS中的全部或部分地址,可以用域名
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://node1:2380"
# 告诉其他etcd,当前etcd与客户端通信的地址列表,也就是ETCD_LISTEN_CLIENT_URLS中的全部或部分地址,可以用域名
ETCD_ADVERTISE_CLIENT_URLS="http://node1:2379"
# 集群中初始成员(etcd),格式为[ETCD_NAME]=[ETCD_LISTEN_PEER_URL],可以用域名
ETCD_INITIAL_CLUSTER="node1=http://node1:2380,node2=http://node2:2380,node3=http://node3:2380"
# 集群初始令牌,每个集群的令牌唯一,集群中所有etcd用相同令牌
ETCD_INITIAL_CLUSTER_TOKEN="etcd-cluster"
# 可选值为new|existing,加入已存在的集群用existing
ETCD_INITIAL_CLUSTER_STATE="new"' > /etc/etcd/etcd.conf

用于监听客户端消息的当前etcd地址表ETCD_LISTEN_CLIENT_URLS配置http://localhost:2379是因为etcdctl默认是通过127.0.0.1:2379来连接Etcd的,不配置那就意味着Etcd没有监听这个地址,etcdctl执行相关命令会连接不上报错。

Error: dial tcp 127.0.0.1:2379: connect: connection refused

image-20211211164125584

启停操作

启动的时候要至少过半的节点启动才会成功,否则执行命令后会卡住不动,因为Etcd遵循Raft协议,要过半节点才能选主和执行写操作。

# 启动
systemctl start etcd

# 启动/重启
systemctl restart etcd

# 停止
systemctl stop etcd

测试

查看集群成员列表

echo '查看集群所有成员状态' > /dev/null
etcdctl -w table endpoint status --cluster 

从结果可以看到每个成员的地址(ENDPOINT)、ID、是否主节点(IS LEADER)等信息。Etcd是基于Raft分布式一致性协议实现的,我们从结果还可以看到任期(RAFT TERM)和日志索引(RAFT INDEX)。

image-20211211154343481

重新选举

从上面结果看到node1为主节点,我们在node1执行下面语句,停掉node1的Etcd,并查看node2和node3的节点状态。

echo 'etcd停止' > /dev/null
systemctl stop etcd

echo '查看node2和node3状态' > /dev/null
etcdctl -w table endpoint status --endpoints=node2:2379,node3:2379

从下面结果可以看到node2成为了主节点,集群进入了下一个任期4

image-20211211155749423

我们通过node1重启它的Etcd,然后看看所有成员的状态。

systemctl start etcd

etcdctl -w table endpoint status --cluster

可以看到主节点不变,还是node2。关注日志索引(RAFT INDEX)可以看到,选主也会导致它自增。

image-20211211160440221

读写数据

任意节点写入的值,都可以在其他节点看到。执行下面脚本前后查看日志索引(RAFT INDEX)会发现值+2,因为有两次写操作putdel

echo '写入键值对name=china' > /dev/null
etcdctl put name china

echo '获取键为name的值' > /dev/null
etcdctl get name

echo '获取所有键值对' > /dev/null
etcdctl get --from-key ''

echo '删除键name' > /dev/null
etcdctl del name

image-20211211161855167

参考

GitHub - etcd

Etcd - 官网

GitHub - etcdctl

Etcd - 配置

GitHub - raft