etcd 是一个高可用的分布式键值(key-value)数据库,采用了更为简洁的Raft共识算法来实现数据强一致。基于Go语言实现,主要用于共享配置和服务发现。
名称 | 说明 |
---|---|
etcd | 一种基于 raft 协议的分布式 kv 数据库,特点是数据强一致性常用于保存配置文件,如作为 Kubernetes 的默认数据库(etcd 即 etc distributed,/etc 是操作系统的配置目录) |
etcdctl | etcd 客户端命令行工具,可以输入命令与 etcd 服务端交互(如同 kubectl同k8s集群交互) |
server | 服务端 |
client | 客户端 |
cluster | 集群,etcd 是一个分布式数据库,由多个节点构成一个集群,作为一个整体提供数据库能力 |
member | 集群成员,其实就是一个 server 节点,更侧重 raft 集群下各节点相互通信保证数据一致性的角度 |
peer | 在同一个集群中,一个 member 将其他 member 视为 peer |
endpoint | 服务节点,其实就是一个 server 节点,更侧重向 client 提供 API 调用的角度 |
leader | 主节点,etcd 集群中只有一个主节点,所有写请求都会先到主节点,由主节点同步数据给从节点 |
follower | 从节点,etcd 集群中可以有若干个 |
revision | etcd 全局版本号,从 1 开始,每次操作数据都会增加 |
snapshot | 快照,保存某一时刻下的系统状态数据,以便可以让 etcd 恢复到该时刻(在此之前的 log 都可以删掉了) |
wal | 预写日志(Write Ahead Log),类似 MySQL 的 redo log,用于保证集群的一致性、可恢复性 |
lease | 租约,是客户端与服务端之间的约定,约定内容是某段时间内数据必须保留,过了这段时间数据可以删掉,起到过期时间的作用 |
checkpoints | 一种保障 lease 的技术手段,leader 定期做 checkpoints,同步给其他 member |
etcd 由多个节点组成一个集群,只要成功向集群写入数据,立刻可以读到刚刚写入的数据,即使发生节点异常、网络分区故障。强一致性,不是指集群内的所有节点在任意时刻状态一致,而是指整个集群看起来像是只有一个数据副本,读写操作都是原子的,不用关心数据同步的。
etcd 内部通过 Raft 算法实现,由该算法保证分布式、强一致性,这种算法的原理可以参考:
《Raft Understandable Distributed Consensus》
《Raft 容易理解的分布式共识算法》(汉化版)
etcd 于 2013 年由 CoreOS 团队发起,2015 年发布第一个正式稳定版本 2.0,2017 年发布 3.0,这两个版本内部实现不同,v2 写入的数据 v3 查不到。本文采用的版本是 比较新的版本3.3。
这里对比一下两个版本的一些区别,也可以看出v3版本做出了哪些优化:
v3版本使用 gRPC + protobuf 取代 v2版本的http + json 通信,提高通信效率。gRPC 只需要一条连接,http是每个请求建立一条连接,建立连接会耗费大量时间;protobuf 加解密比json加解密速度得到数量级的提升,包体也更小。
v3 使用 lease (租约)替换v2中key ttl自动过期机制,后面会介绍。
v3 是支持事务和多版本并发控制mvcc(解决一致性非锁定读的问题)的磁盘数据库,而 v2 是简单的kv内存数据库
v3 是扁平的kv结构,v2是类型文件系统的存储结构,类似zookeeper的存储结构。v3版本使用__prefix前缀索引的方式实现了以往v2版本实现的文件系统的存储结构。
关于etcd集群搭建在这就省略了,大家可以自己搭建单节点的集群测试。我就使用之前搭建kubernetes集群时使用的etcd服务。
为方便使用,先设置一下 etcd_v2/ etcd_v3的别名,大家可以根据自己集群的实际情况设置
cat <<EOF > /etc/profile.d/etcd.sh
alias etcd_v2='etcdctl --cert-file /etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key-file /etc/kubernetes/pki/etcd/healthcheck-client.key \
--ca-file /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://192.168.2.140:2379,https://192.168.2.141:2379,https://192.168.2.142:2379'
alias etcd_v3='ETCDCTL_API=3 \
etcdctl \
--cert /etc/kubernetes/pki/etcd/healthcheck-client.crt \
--key /etc/kubernetes/pki/etcd/healthcheck-client.key \
--cacert /etc/kubernetes/pki/etcd/ca.crt \
--endpoints https://192.168.2.140:2379,https://192.168.2.141:2379,https://192.168.2.142:2379'
EOF
source /etc/profile.d/etcd.sh
然后测试读写
[root@k8s-m1 tmp]# etcd_v3 put aaa 111
OK
[root@k8s-m1 tmp]# etcd_v3 get aaa
aaa
111
etcd 保存的数据有版本号,可以指定版本读取历史数据(如果不压缩清除历史版本的数据),如果不指定,默认读取最大版本的数据:
写数据
[root@k8s-m1 tmp]# etcd_v3 put aaa 222 -w json
{"header":{"cluster_id":9189981678766318811,"member_id":7409550525054359918,"revision":89481299,"raft_term":267804}}
[root@k8s-m1 tmp]# etcd_v3 put aaa 333 -w json
{"header":{"cluster_id":9189981678766318811,"member_id":1864273196654539866,"revision":89481333,"raft_term":267804}}
指定版本读取读数据
[root@k8s-m1 tmp]# etcd_v3 get aaa --rev=89481299
aaa
222
[root@k8s-m1 tmp]# etcd_v3 get aaa --rev=89481333
aaa
333
#默认最新
[root@k8s-m1 tmp]# etcd_v3 get aaa
aaa
333
插入一些测试数据
[root@k8s-m1 tmp]# etcd_v3 put bbb 444
[root@k8s-m1 tmp]# etcd_v3 put ccc 555
[root@k8s-m1 tmp]# etcd_v3 put ddd 666
[root@k8s-m1 tmp]# etcd_v3 put eee 777
[root@k8s-m1 tmp]# etcd_v3 put fff 888
[root@k8s-m1 tmp]# etcd_v3 put aa1 999
[root@k8s-m1 tmp]# etcd_v3 put aa2 1010
[root@k8s-m1 tmp]# etcd_v3 put cc1 1111
[root@k8s-m1 tmp]# etcd_v3 put dd2 1212
按key前缀查看
[root@k8s-m1 tmp]# etcd_v3 get --prefix aa
aa1
999
aa2
1010
aaa
333
按key的字节排序的前缀查找>=
[root@k8s-m1 tmp]# etcd_v3 get --from-key aaa
aaa
333
bbb
444
cc1
1111
ccc
555
compact_rev_key
89481477
dd2
1212
ddd
666
eee
777
fff
888
foo
bar2
按key的字节排序区间查找<= value <
[root@k8s-m1 tmp]# etcd_v3 get ccc eee
ccc
555
compact_rev_key
89481477
dd2
1212
ddd
666
查找所有key
#key太多,查看起来很不方便
[root@k8s-m1 tmp]# etcdctl get --from-key ""
删除指定key
#返回1 代表正常删除key的数量
[root@k8s-m1 tmp]# etcd_v3 del aa1
1
删除key时并返回被删除的键值对
[root@k8s-m1 tmp]# etcd_v3 del aa2 --prev-kv
1
aa2
1010
删除指定前缀的key
#删除了2个
[root@k8s-m1 tmp]# etcd_v3 del --prefix cc
2
删除所有数据
#危险操作,谨慎
[root@k8s-m1 tmp]# etcd_v3 del --prefix ""
[root@k8s-m1 tmp]# etcd_v3 get aaa
aaa
333
[root@k8s-m1 tmp]# etcd_v3 put aaa test
OK
[root@k8s-m1 tmp]# etcd_v3 get aaa
aaa
test
#只查看所有的key
[root@k8s-m1 tmp]# etcd_v3 get / --prefix --keys-only
#查看节点
[root@k8s-m1 tmp]# etcd_v3 member list
19df3a9852e0345a, started, etcd0, https://192.168.2.140:2380, https://192.168.2.140:2379
3bb3629d60bef3f6, started, etcd2, https://192.168.2.142:2380, https://192.168.2.142:2379
66d402f1ef2c996e, started, etcd0, https://192.168.2.141:2380, https://192.168.2.141:2379
#查看节点状态
[root@k8s-m1 tmp]# etcd_v3 endpoint health
https://192.168.2.141:2379 is healthy: successfully committed proposal: took = 3.200938ms
https://192.168.2.140:2379 is healthy: successfully committed proposal: took = 3.421955ms
https://192.168.2.142:2379 is healthy: successfully committed proposal: took = 1.915926ms
记不住命令的可以通过etcd_v3 -h查看帮助选项
#备份,只需要在一台上执行
ETCDCTL_API=3 etcdctl --cert /etc/kubernetes/pki/etcd/healthcheck-client.crt --key /etc/kubernetes/pki/etcd/healthcheck-client.key --cacert /etc/kubernetes/pki/etcd/ca.crt --endpoints https://192.168.2.140:2379,https://192.168.2.141:2379,https://192.168.2.142:2379 snapshot save test.db
#恢复,三个节点都需要执行
ETCDCTL_API=3 etcdctl --name k8s-m1 --initial-advertise-peer-urls https://192.168.2.140:2380 --initial-cluster k8s-m1=https://192.168.2.140:2380,k8s-m2=https://192.168.2.141:2380,k8s-m3=https://192.168.2.142:2380 snapshot restore /root/test.db --data-dir=/var/lib/etcd/
更多关于kubernetes的知识分享,请前往博客主页。编写过程中,难免出现差错,敬请指出