etcd作为一个分布式键值对存储数据库,它适用的场景有很多。分布式锁、服务发现与注册、键值对存储、消息发布订阅。
etcd的使用场景
分布式锁:
因为etcd使用Raft算法保持了数据的强一致性,其次操作存储到集群中的值必然是全局一致的,所以很容易实现分布式锁。锁服务有两种使用方式,一是保持占有,二是控制时序(TTL)。而且它支持CAS(compare and swap)和compare and delete指令,使得它检查某个值是否存在和赋值是在同一个指令里面操作完成、也有响应的lease对象进行续约。
TTL指的是给一个key设置一个有效期,到期后这个key就会被自动删掉,这在很多分布式锁的实现上(Redis)都会用到,可以保证锁的实时有效性。
服务发现与注册:
服务发现主要解决在同一个分布式集群中的进程或服务,要如何才能找到对方并建立链接。本质上来说,服务发现就是要了解集群中是否有进程在监听udp或tcp端口,并且通过名字就可以查找和连接。
消息发布订阅:
在分布式系统中,最适用的一种组件间通信方式就是消息发布与订阅。即构建一个配置共享中心,数据提供者在这个配置中心发布消息,而消息使用者则订阅他们关心的主题,一旦主题有消息发布,就会实时通知订阅者。通过这种方式可以做到分布式系统配置的集中式管理与动态更新。应用中用到的一些配置信息放到etcd上进行集中管理。
- 键值对存储:
- 支持并发1k/s的写操作,2k+/s的读操作。
- 采用KV类型数据存储,一般情况下,比关系型数据库快。
- 支持动态存储(内存)以及静态存储(硬盘)。
- 存储方式,采用类似目录结构(B+Tree)
- 只有叶子节点才能存储数据,相当于文件
- 叶子节点的父节点一定是目录,目录不能存储数据
Raft算法
Raft协议是基于quorum机制,即大多数同意原则,任何的变更都需要超过半数的成员确认。
对象介绍
Follower:追随者,即从领导接收数据,并且同步到自己的blotDb。不接收数据变更,如果有数据发送给它,则会通过一致性模块转发给leader,由leader完成数据一致性保证。
Leader:领导者,接收数据并且把数据同步给其他Follower,超过半数Follower确认之后,写入WAL。
Candidate:竞选者,当集群里面没有leader,或者在心跳周期内没收到主节点发送的心跳,则起一个随机时间数(150ms~300ms)发起投票,它首先会投自己一票,然后再发起对其他Follower发起投票,如果超过半数(n/2+1)个同意,则增加leader任期,然后成为Leader。
Learner:学习者,Raft 4.2.1引入的新角色,由于网络问题导致该Follower长时间获取不到同步数据,则该Follower会变为Learner。Learner由于落后太多,不会参与竞选。只是一直的同步数据。
日志复制
- 当Leader接收到数据后,先写入到WAL然后把数据通过心跳的方式一起传给Follower。
- Follower接收到数据后,也写入到自己的WAL。然后通过心跳方式回传给Leader,告诉Leader数据已确认(需要多数Follower确认)。
- Leader接收到确认信息后,将该日志改为Commit状态,然后再通过心跳的方式通知给Follower该数据已Commit。
- Follower接收到Leader发来的Commit,也将自己日志改为Commit。
选主流程
假如有A、B、C三个Follower。
- 集群启动时,全部都为Follower。
- Follower由于在心跳超时时间没收到Leader的心跳。
- 将150ms~300ms的随机时间内发起Candidate投票,比如B节点的随机时间比较短,则首先称为Candidate。
- B节点将发送选主请求给到A和C,A、C接收选主请求之后,给B节点进行投票。
- 则B节点获得大多数人的投票,则称为Leader。
- B一直发送心跳给A、C保持Leader状态。
注意事项:
1、投票需要获得n/2+1个投票,所以建议集群为单数,一般3个或者5个。
2、如果由于节点Down了,导致集群个数为偶数,则有可能会陷入多次选主。即出现多次投票结果出现一致票数。(无效投票)
3、参与选主还需要有一定的条件。(任期Term、日志Committed log)
WAL (Write ahead log)
- wal 日志是二进制的,解析出来后是数据结构LogEntry,数据结构如下表:
- type:0表示Normal,1表示ConfChange(配置变更、新节点加入、减节点)。
- term:代表主节点的任期,每次主节点变更term会增加。
- index:有序递增的序号。用来记录commit log id。
- data:以pb结构保存数据。
Entry | |||
type | term | index | data |
walLog 落盘是由fsync触发的
MVCC模块
保存了每个版本的信息
键值为key,val为revision的最新版本号。
如:写入了a=11,则当前reversion为5,则key=a,val=5
BlotDb
key-value键值对的数据库,类似B+tree方式保存数据,
- 只有叶子节点才能存储数据,相当于文件
- 叶子节点的父节点一定是目录,目录不能存储数据
保存了key和每个版本的值及create_version,mod_version的值,当前version和value.
数据示例:
{
"kvs":[
{
"key":"a",
"create_revision":2,
"mod_revision":2,
"version":5,
"value":"11"
}
]
}