我们之前学习zookeeper集群节点搭建时一直都是搭建集群数为2n+1,不管是自己搭建还是公司搭建都是2n+1,至于为什么是2n+1一直都是一个模糊的概念,今天我重点学习了一下zookeeper翻阅了大量的资料大概理解了一下,现将其整理记录下来。
首先我们要先理解一下zookeeper的选举机制
得到的票数/集群的总数 > 50%就成leader(这句话很关键)
所以这个时候建议服务器性能比较好,设置他的id值大一些
当我们了解了zookeeper选举机制后就能来讲为什么集群需要2n+1个
1、防止由脑裂问题造成的集群不可用。
关于脑裂首先我们来讲一下什么是脑裂
在"双机热备"高可用(HA)系统中,当联系两个节点的"心跳线"断开时(即两个节点断开联系时),本来为一个整体、动作协调的HA系统,就分裂成为两个独立的节点(即两个独立的个体)。由于相互失去了联系,都以为是对方出了故障,两个节点上的HA软件像"裂脑人"一样,“本能"地争抢"共享资源”、争起"应用服务"。就会发生严重后果:
1)或者共享资源被瓜分、两边"服务"都起不来了;
2)或者两边"服务"都起来了,但同时读写"共享存储",导致数据损坏(常见如数据库轮询着的联机日志出错)。两个节点相互争抢共享资源,结果会导致系统混乱,数据损坏。对于无状态服务的HA,无所谓脑裂不脑裂,但对有状态服务(比如MySQL)的HA,必须要严格防止脑裂
[但有些生产环境下的系统按照无状态服务HA的那一套去配置有状态服务,结果就可想而知]
首先,什么是脑裂?集群的脑裂通常是发生在节点之间通信不可达的情况下,集群会分裂成不同的小集群,小集群各自选出自己的master节点,导致原有的集群出现多个master节点的情况,这就是脑裂。
脑裂导致的问题
引起数据的不完整性:集群中节点(在脑裂期间)同时访问同一共享资源,而且没有机制去协调控制的话,那么就存在数据的不完整性的可能。
服务异常:对外提供的服务出现异常。
现在我们来说一下现在我们来说一下Zookeeper 集群中的"脑裂"场景说明
对于一个集群,想要提高这个集群的可用性,通常会采用多机房部署,比如现在有一个由6台zkServer所组成的一个集群,部署在了两个机房:
正常情况下,此集群只会有一个Leader,那么如果机房之间的网络断了之后,两个机房内各自的zkServer还是可以相互通信的,如果不考虑过半机制,那么就会出现每个机房内部根据选举都将选出一个Leader。这就是信息不可达问题
这就相当于本来是同一个集群的,被分成了不同的两个集群,两个集群都根据选举出现了两个leader,这就是脑裂现象。对于这种情况,其实也可以看出来,原本应该是统一的一个集群对外提供服务的,现在变成了两个集群同时对外提供服务,如果过了一会,断了的网络突然联通了,那么就会出现问题,两个集群刚刚都对外提供服务了,两个机房中谁才是那个leader ,数据该由谁去解决,数据冲突问题怎么解决。
在集群中单机房中也会出现脑裂问题
我们从上述简介中可以知道,假设一个集群、动作协调的节点A和节点B,节点A和B之间通过heartBeat来检查对方的存活状态,负责协调保证整个集群服务的可用性。正常情况下,如果节点A通过心跳检测不到B的存在的时候,就会接管B的资源,同理节点B检查不到B的存活状态的时候也会接管A的资源。如果出现网络故障,就会导致A和B同时检查不到对方的存活状态认为对方出现异常,这个时候就会导致A接管B的资源,B也会接管A的资源。也会出现多个leader的情况
原本是统一的一个集群对外提供服务的,现在变成了两个集群同时对外提供服务,两个集群都对外提供服务了,这就是脑裂导致的信息不一致。
下面举例说一下为什么采用奇数台节点,就可以防止由于脑裂造成的服务不可用:
(1) 假如zookeeper集群有 5个节点,分别放在了不同的机房假设机房中放的个数不同(这样也模模拟出了 同一机房发生脑裂的问题),现在网络突然波动,发生了脑裂,脑裂成了A、B两个小集群:
第一种情况 A机房 : 1个节点 ,B 机房:4个节点
第二种情况 A机房 : 2个节点, B机房 :3个节点
可以看出,上面这两种情况下当网络恢复时,A、B中总会有一个小集群满足 可用节点数量 > 总节点数量/2。所以zookeeper集群仍然能够选举出leader , 仍然能对外提供服务,并且能整合数据,只不过是有一部分节点失效了而已。
(2) 假如zookeeper集群有4个节点,同样发生脑裂,脑裂成了A、B两个小集群:
第一种情况 A机房 : 1个节点 ,B 机房:3个节点
第二种情况 A机房 : 2个节点, B机房 :2个节点
可以看出,情况1 是满足选举条件的,与(1)中的例子相同。 但是情况2 就不同了,因为A和B都是2个节点,都不满足 可用节点数量 >总节点数量/2 的选举条件, 所以此时zookeeper就彻底不能提供服务了。
在同一个机房中也是一样的,在奇数个服务器中,不管脑裂成什么情况个数不同的集群,只要是集群多的推选出leader票数必定大于1/2。
所以综合上面两个例子可以看出: 在节点数量是奇数个的情况下, zookeeper集群总能对外提供服务(即使损失了一部分节点);如果节点数量是偶数个,会存在zookeeper集群不能用的可能性(脑裂成两个均等的子集群的时候)。
在生产环境中,如果zookeeper集群不能提供服务,那将是致命的 , 所以zookeeper集群的节点数一般采用奇数个。
2、在容错能力相同的情况下,奇数台更节省资源。
(1) 假如zookeeper集群1 ,有3个节点,3/2=1.5 , 即zookeeper想要正常对外提供服务(即leader选举成功),至少需要2个节点是正常的。换句话说,3个节点的zookeeper集群,允许有一个节点宕机。
(2) 假如zookeeper集群2,有4个节点,4/2=2 ,
即zookeeper想要正常对外提供服务(即leader选举成功),至少需要3个节点是正常的。换句话说,4个节点的zookeeper集群,也允许有一个节点宕机。
那么问题就来了, 集群1与集群2都有
允许1个节点宕机的容错能力,但是集群2比集群1多了1个节点。在相同容错能力的情况下,本着节约资源的原则,zookeeper集群的节点数维持奇数个更好一些。
3.确保事务能够顺利进行
先看图再分析 |
---|
对于zookeeper的 create, setData, delete 等有写操作的请求,则需要统一转发给leader 处理, leader
需要决定编号、执行操作,这个过程称为一个事务。ZAB的事务2pc, 3pc(TCC)
举个例子写操作时leader写数据,发送给集群中的其他服务进行写的操作。其他服务器写完要返回结果给leader成功或者是失败,如果超过50%写成功了,leader就认为这次写操作成,返回给客户端操作成功。如果收到的成功率没有超过50%,认为操作失败,发送请求让所有集群中的其他服务进行回滚操作(2pc协议)
根据上述描述我们可以清楚的了,假设我们搭建的zookeeper节点是6台服务器的话在进行,在进行事务操作时只有2台收到了成功,这个时候成功的zookeeper服务器一共有三台(包括leader自己)那么此时3/6=50% 的这个时候就没办法判断是否成功
当节点是奇数时就可以准确的得知是否操作成功。
假设有7台服务器,在进行操作时有3台服务器读取成功,这个时候一共有四台服务器读取成功4/7>50%当只有2台成功时3/7<50%,那么就可以很简单的判断出写操作是否成功
扩展知识内容 |
---|
1.zookeeper核心
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者 崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
• 为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
2、Zookeeper 的读写机制
» Zookeeper是一个由多个server组成的集群
» 一个leader,多个follower
»每个server保存一份数据副本
» 全局数据一致
» 分布式读写
» 更新请求转发,由leader实施
3、Zookeeper 的保证
» 更新请求顺序进行,来自同一个client的更新请求按其发送顺序依次执行
» 数据更新原子性,一次数据更新要么成功,要么失败
» 全局唯一数据视图,client无论连接到哪个server,数据视图都是一致的
» 实时性,在一定事件范围内,client能读到最新数据
4、Zookeeper节点数据操作流程
1.在Client向Follwer发出一个写的请求
2.Follwer把请求发送给Leader
3.Leader接收到以后开始发起投票并通知Follwer进行投票
4.Follwer把投票结果发送给Leader
5.Leader将结果汇总后如果需要写入,则开始写入同时把写入操作通知给Leader,然后commit;
6.Follwer把请求结果返回给Client