ETCD和Zookeeper的对比(一)


前言

最近开发工作中使用到了etcd作为注册中心,简单的了etcd作为注册中心与我们常用的zookeeper有什么区别。


1、分布式一致性算法

1.1、为什么需要一致性

为了高可用和数据安全起见,分布式的集群一般都是由几个节点构成。多节点证明它们之间肯定会有数据的通信,同时,为了能够使集群对外是透明的,一个整体对外提供服务,那么客户端访问服务端的数据肯定是要数据同步,也即数据一致性

1.2、zab协议

zk集群是Leader/Follower模式来保证数据同步的。整个集群同一时刻只能有一个Leader,其他都是Follower或Observer。Leader是通过选举选出来的,这里涉及到ZAB协议(原子消息广播协议)。
zab的概念:所有事务请求是由一个全局唯一的服务器来协调处理,这个的服务器就是Leader服务器,其它服务器都是Follower服务器或Observer服务器。Leader服务器负责将一个客户端的请求转换成那个一个事务Proposalͧ(提议),将该Proposal分发给集群中所有的Follower服务器。然后Leader服务器需要等待所有Follower服务器的应答,当Leader服务器收到超过半数的Follower服务器进行了明确的应答后,Leader会再次向所有的Follower服务器分发Commit消息,要求其将前一个Proposal进行提交。
总的来说就是,涉及到客户端对zk集群数据改变的行为都先由Leader统一响应,然后再把请求转换为事务转发给其他所有的Follower,Follower应答并处理事务,最后再反馈。如果客户端只是读请求,那么zk集群所有的节点都可以响应这个请求。

1.2.1 选主过程

ZAB协议三个阶段:

  1. 发现(选举Leader过程)
  2. 同步(选出Leader后,Follower和Observer需进行数据同步)
  3. 广播(同步之后,集群对外工作响应请求,并进行消息广播,实现数据在集群节点的副本存储)

选主原则如下(在选举时,对比次序是从上往下)

  1. 主周期更大,代所有一切是最新,就成为leader
  2. 主周期一致就是在同一轮选票中,zxid越大就成为leader,因为数据更新主周期和zxid一致,就看机器的id(myid),myid越大就成为leader
  3. 同时,在选举的时候是投票方式进行的,除主进程周期外,投票格式为(myid,zxid)。

注:zxid由两部分构成:主进程周期epoch和事务单调递增的计数器。zxid是一个64位的数,高32位代表主进程周期epoch,低32位代表事务单调递增的计数器。
主进程周期epoch也叫epoch,是选举的轮次,每选举一次就递增1。事务单调递增的计数器在每次选举完成之后就会从0开始。

1.2.2 选主过程

  • 集群选举完成,并且完成数据同步后,开始对外服务,接收读写请求
  • 当leader接收到客户端新的事务请求后,会生成对新的事务proposal,并根据zxid的顺序向所有的
    follower分发事务proposal
  • 当follower收到leader的proposal时,根据接收的先后顺序处理proposal
  • 当Leader收到follower针对某个proposal过半的ack后,则发起事务提交,重新发起一个commit的 proposal
  • Follower收到commit的proposal后,记录事务提交,并把数据更新到内存数据库

1.3、raft协议

每一个 Raft 集群中都包含多个服务器,在任意时刻,每一台服务器只可能 处于 Leader、Follower 以及 Candidate 三种状态;在处于正常的状态时,集群中只会存在一个 Leader,其余的服务器都是 Follower。

所有的 Follower 节点都是被动的,它们不会主动发出任何的请求,只会响应 Leader 和 Candidate 发出的请求,对于每一个用户的可变操作,都会被路由给 Leader 节点进行处理,除了 Leader 和 Follower 节点之外,Candidate 节点其实只是集群运行过程中的一个临时状态。

Raft 集群中的时间也被切分成了不同的几个任期(Term),每一个任期都会由 Leader 的选举开始,选举结束后就会进入正常操作的阶段,直到 Leader 节点出现问题才会开始新一轮的选择。

每一个服务器都会存储当前集群的最新任期,它就像是一个单调递增的逻辑时钟,能够同步各个节点之间的状态,当前节点持有的任期会随着每一个请求被传递到其他的节点上。

Raft 协议在每一个任期的开始时都会从一个集群中选出一个节点作为集群的 Leader 节点,这个节点会负责集群中的日志的复制以及管理工作。
我们将 Raft 协议分成三个子问题:节点选举、日志复制以及安全性,文章会以 etcd 为例介绍 Raft 协议是如何解决这三个子问题的。

1.3.1选主过程

Raft协议是用于维护一组服务节点数据一致性的协议。这一组服务节点构成一个集群,并且有一个主节点来对外提供服务。当集群初始化,或者主节点挂掉后,面临一个选主问题。集群中每个节点,任意时刻处于Leader, Follower, Candidate这三个角色之一。选举特点如下:

  • 当集群初始化时候,每个节点都是Follower角色;
  • 集群中存在至多1个有效的主节点,通过心跳与其他节点同步数据
  • 当Follower在一定时间内没有收到来自主节点的心跳,会将自己角色改变为Candidate,并发起一次选主投票;当收到包括自己在内超过半数节点赞成后,选举成功;当收到票数不足半数选举失败,或者选举超时。若本轮未选出主节点,将进行下一轮选举(出现这种情况,是由于多个节点同时选举,所有节点均为获得过半选票)。
  • Candidate节点收到来自主节点的信息后,会立即终止选举过程,进入Follower角色。
    为了避免陷入选主失败循环,每个节点未收到心跳发起选举的时间是一定范围内的随机值,这样能够避免2个节点同时发起选主。

1.3.2主从数据同步

  • client连接follower或者leader,如果连接的是follower则,follower会把client的请求(写请求,读请求则自身就可以直接处理)转发到leader
  • leader接收到client的请求,将该请求转换成entry,写入到自己的日志中,得到在日志中的index,会将该entry发送给所有的follower(实际上是批量的entries)
  • follower接收到leader的AppendEntries
    RPC请求之后,会将leader传过来的批量entries写入到文件中(通常并没有立即刷新到磁盘),然后向leader回复OK
  • leader收到过半的OK回复之后,就认为可以提交了,然后应用到leader自己的状态机中,leader更新commitIndex,应用完毕后回复客户端
  • 在下一次leader发给follower的心跳中,会将leader的commitIndex传递给follower,follower发现commitIndex更新了则也将commitIndex之前的日志都进行提交和应用到状态机中

2、其他

1、etcd支持mvcc,通过两个b+tree进行版本控制,zk不自持。
2、etcd默认对外提供gRpc接口访问,gRPC可以序列化成Json,通过http传输,所以Curl等命令行的命令也可以访问;zk则必须要使用自己的client进行调用。
3、etcd有分布式存储功能,对于大数据存储写入性能会比zk要好很多。
4、etcd更加轻量。
5、watch机制方main更加优秀,下一篇文章分析。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐