1. 简述
服务节点是临时节点,当服务在一定时间内没有发送心跳包,则立马剔除
zookeeper从设计者模式角度出发来理解,是一个基于观察者模式设计的分布式服务管理框架
他负责存储和管理大家都关心的数据,然后接收观察者的注册,一旦这些数据发生变化,zookeeper就将负责通知已经在zookeeper上注册的那些观察者做出的相应的反应。
2. 下载并安装
1.第一步,在官网下载相关安装包
https://zookeeper.apache.org/releases.html
2.第二步,找一个自己熟悉的文件夹路径,将下载好的包放入
使用 tar -zxvf apache-zookeeper-3.6.2-bin.tar.gz
3.第三步,解压完之后,cd 进入解压完的包内,在里面创建2个文件夹 data 和logs
4.第四步,cd conf 进入conf配置文件夹,里面有一个zoo_sample.cfg 文件,将其拷贝改名为zoo.conf
cp zoo_sample.cfg zoo.cfg
5.第五步,vi 修改zoo.conf配置,在里面添加红框内容
解析:
-
tickTime=2000
代表心跳时间,2秒钟一个心跳 -
initLimit=10
代表心跳针,,10个心跳针,10*2s=20s
也就是说如果Follower如果20s之内没有联系Learder,那么learder会认为找不到了该Follower -
syncLimit=5
集群启动后的心跳针,也就是5*2s=10s
跟上面同理,为什么这里是10s,上面是20s,因为项目启动比较耗时 -
clientPort=2181
监听客户端访问服务端的端口号
server.1=192.168.248.128:2888:3888- 2888 端口号是zookeeper服务之间通信的端口
- 3888 是zookeeper 与其他应用程序通信的端口
-
server.A=B:C:D
- 其中 A 是一个数字,表示这个是第几号服务器;
- B 是这个服务器的IP地址或/etc/hosts文件中映射了IP的主机名;
- C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;
- D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行举时服务器相互通信的端口。
如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。
-
initLimit=10:LF
初始通信时限集群中的Follower跟随者服务器与Leader领导者服务器之间初始连接时能容忍的最多心跳数(tickTime的数量),用它来限定集群中的Zookeeper服务器连接到Leader的时限。 -
syncLimit =5:LF
同步通信时限
集群中Leader与Follower之间的最大响应时间单位,假如响应超过syncLimit ,Leader认为Follwer死掉,从服务器列表中删除Follwer。 -
dataDir
数据文件目录+数据持久化路径
主要用于保存Zookeeper中的数据。 -
clientPort=2181
客户端连接端口,监听客户端连接的端口。
5.第六步,进入到刚创建的data文件夹,使用 touch myid 创建myid的text文件,在里面输入1并保存
6.第七步,修改系统环境变量配置文件
vi ~/.bash_profile
7.第八步,刷新刚刚修改的配置文件 source ~/.bash_profile
8.第九步,关闭防火墙 service iptables stop 关闭开机自启 chkconfig iptables off
9.第十步,进入bin包下,使用zkServer.sh start 命令,不要使用./zkServer.sh
查看状态
3. 引入依赖并修改Yml
<!--zookeeper-discovey-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
</dependency>
server:
port: 8003
spring:
application:
name: cloud-payment-service8003
cloud:
zookeeper:
connect-string: 192.168.2.133:2181 //ip为zookeeper所在ip,端口默认开始2181
4. 查看是否注入
4.1启动
4.2查看服务是否被注册进去
- ls / 查看zookeeper的根目录
- ls /节点名称 查看具体注册服务
只要有服务进来,内部会生成流水号,通过流水号可以查询节点信息,证明已经成功注入进zookeeper
4.3 服务启动的时候可能会出现的问题
可能会出现jar包异常
原因是我们导入的zookeeper依赖自带的依赖版本和在Linux上安装的不一致,导致版本冲突
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zookeeper-discovery -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
<!--排除zk自带的3.5.3-->
<exclusions>
<exclusion>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--添加咱门linux上安装的zk 3.4,9版本-->
<!-- https://mvnrepository.com/artifact/org.apache.zookeeper/zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.9</version>
</dependency>
5. 特点
- Zookeeper:一个领导者(Leader),多个跟随者(Follower)组成的集群。
- 集群中
只要有半数以上
节点存活(假设5个挂3个,不能正常服务,4个挂2个,可以正常服务,注意:半数以上),Zookeeper集群就能正常服务。 - 全局数据一致:每个Server保存一份相同的数据副本(数据会不会很大?不会,因为它不是真正的保存教据,而是保存一些核心配置文件),Client无论连接到哪个Server,数据都是一致的。
- 更新请求顺序进行,来自同一个Client的更新请求按其发送顺序依次执行。
- 数据更新原子性,一次数据更新要么成功,要么失败。 (
事务
) - 实时性,在一定时间范围内,Client能读到最新数据。 (同步非常快)
6 数据结构
ZooKeeper数据模型的结构与Unix文件系统很类似
,整体上可以看作是一棵树,每个节点称做一个ZNode。每一个ZNode默认能够存储1MB
的数据,每个ZNode都可以通过其路径唯一标识
。
7 应用场景
7.1 统一命名服务
7.2 统一配置管理
7.3 统一集群管理
7.4 监听服务器的动态上下线
7.5 软负载均衡
硬负载均衡和软负载均衡
- 什么是软负载均衡及常用方式?
在系统服务器上安装相应负载均衡软件进行相关的配置达到均衡负载的目的。它基于特定的使用环境配置简单使用灵活成本较低,能够解决大部分需求问题。常用的软件有:Nginx - 什么是硬负载均衡及常用的设备?
硬件负载均衡是直接在服务器和外部网络间安装负载均衡设备。常用的硬件设备有:F5
什么是F5?
F5负载均衡器是应用交付网络的全球领导者F5 Networks公司提供的一个负载均衡器专用设备,F5 BIG-IP LTM的官方名称叫做本地流量管理器,可以做4-7层负载均衡,具有负载均衡、应用交换、会话交换、状态监控、智能网络地址转换、通用持续性、响应错误处理、IPv6网关、高级路由、智能端口镜像、 SSL加速、智能HTTP压缩、TCP优化、第7层速率整形、内容缓冲、内容转换、连接加速、高速缓存、
Cookie加密、选择性内容加密、应用攻击过滤、拒绝服务(DoS)攻击和SYN Flood保护、防火墙一包过滤.包消毒等功能。
- 有什么优点?
能够直接通过智能交换机实现,处理能力更强,而且与系统无关,负载性能强更适用于一大堆设备、大访问量、简单应用。 - 有什么缺点?
成本高,设备价格高; 配置复杂冗余;
8 内部原理:选举机制
- 半数机制:集群中半数以上机器存活,集群可用。所以Zookeeper 适合安装奇数台
服务器。。 - Zookeeper虽然在配置文件中并没有指定Master和 Slave。但是,Zookeeper 工作时,是有一个节点为Leader,其他则为Follower,Leader是通过内部的选举机制临时产生的。
选举机制简单版: 假设有5台机器,编号1,2,3,4,5 1号先来,先投自己,发现票数没超过半数,放弃,2号
来了,2号先投自己,1号因为自己废了,也投id大的,此时2号id大,就投2号,此时2号有2票,但是没超过半数,没用,3号来了,3号投自己先,然后1,2号也投3号,此时3号有3票,超过半数,Leader就它了
二、选举流程简述
目前有5台服务器,每台服务器均没有数据,它们的编号分别是1.23.45.按编号依次启动,它们的选择举过程如下:
- 服务器1启动,给自己投票,然后发投票信息,由于其它机器还没有启动所以它收不到反馈信息,服务器1的状态一直属于Looking(选举状态)。
- 服务器2启动,给自己投票,同时与之前启动的服务器1交换结果,由于服务器2的编号大所以服务器2胜出,但此时投票数没有大于半数,所以两个服务器的状态依然是LOOKING。
- 服务器3启动,给自己投票,同时与之前启动的服务器12交换信息,由于服务器3的编号最大所以服务器3胜出,此时投票数正好大于半数,所以服务器3成为领导者,服务器1.2成为小弟。
- 服务器4启动,给自己投票,同时与之前启动的服务器1.2.3交换信息,尽管服务器4的编号大,但之前服务器3已经胜出,所以服
务器4只能成为小弟。 - 服务器5启动,后面的逻辑同服务器4成为小弟。
三、选择机制中的概念
-
Serverid: 服务器ID
比如有三台服务器,编号分别是123。
编号越大在选择算法中的权重越大。 -
Zxid: 数据ID
服务器中存放的最大数据ID
值越大说明数据越新,在选举算法中数据越新权重越大 -
Epoch:逻辑时钟
或者叫投票的次数,同一轮投票过程中的逻辑时钟值是相同的。每投完一次票这个数据就会增加,然后与接收到的其它服务器返回的投票信息中的数值相比,根据不同的值做出不同的判断。
- Server状态:选举状态
- LOOKING,竞选状态。
- FOLLOWING,随从状态,同步leader状态,参与投票
- OBSERVING,观察状态,同步leader状态,不参与投票。
- LEADING,领导者状态
四、选举消息内容
在投票完成后,需要将投票信息发送给集群中的所有服务器,它包含如下内容。
- 服务器ID
- 数据ID
- 逻辑时钟
- 选举状态
9. 节点类型
10 相关知识点简述回答
10.1 Zookeeper的工作原理
- Zookeeper的核心是
原子广播
,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议
。 - Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
- Zab协议 的全称是 Zookeeper Atomic Broadcast(Zookeeper原子广播)。
- Zookeeper 是
通过Zab 协议来保证分布式事务的最终一致性
。 - Zab协议要求每个 Leader 都要经历三个阶段:
发现
,同步
,广播
。
当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。
状态同步保证了leader和Server具有相同的系统状态。
为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。
所有的提议(proposal)都在被提出的时候加 上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一 个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。
-
epoch:可以理解为皇帝的年号,当新的皇帝leader产生后,将有一个新的epoch年号。
-
每个Server在工作过程中有四种状态:
-
LOOKING:当前Server不知道leader是谁,正在搜寻。
-
LEADING:当前Server即为选举出来的leader。
-
FOLLOWING:leader已经选举出来,当前Server与之同步。
-
OBSERVING:观察者状态;表明当前服务器角色是 Observer
-
10.2 Zookeeper 的通知机制
Zookeeper 允许客户端向服务端的某个 znode 注册一个 Watcher 监听,当服务端的一些指定事件,触发了这个 Watcher ,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据 Watcher 通知状态和事件类型做出业务上的改变。
大致分为三个步骤:
-
客户端注册 Watcher
-
调用 getData、getChildren、exist 三个 API ,传入Watcher 对象。
-
标记请求request ,封装 Watcher 到 WatchRegistration 。
-
封装成 Packet 对象,发服务端发送request 。
-
收到服务端响应后,将 Watcher 注册到 ZKWatcherManager 中进行管理。
-
请求返回,完成注册。
-
-
服务端处理 Watcher
-
服务端接收 Watcher 并存储。
-
Watcher 触发
-
调用 process 方法来触发 Watcher 。
-
-
客户端回调 Watcher
-
客户端 SendThread 线程接收事件通知,交由 EventThread 线程回调Watcher 。
-
客户端的 Watcher 机制同样是一次性的,一旦被触发后,该 Watcher 就失效了。
-
小总结:
- client 端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些 client 会收到 zk 的通知,然后 client 可以根据 znode 变化来做出业务上的改变等;
- Zookeeper 对节点的 watch 监听通知不是永久的,而是一次性的。无论是服务端还是客户端,一旦一个 Watcher 被触发, Zookeeper 都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。
10.3 选举机制
Zookeeper 有两种选举算法:基于 basic paxos 实现和基于 fast paxos 实现。默认为 fast paxos;
要求集群中的机器为奇数,也是为了选举算法;
10.4 事务的顺序一致性
Zookeeper 采用了递增的事务 id 来识别,所有的 proposal (提议)都在被提出的时候加上了zxid 。
zxid 实际上是一个 64 位数字。高 32 位是 epoch 用来标识 Leader 是否发生了改变,如果有新的Leader 产生出来, epoch 会自增。 低 32 位用来递增计数。 当新产生的 proposal 的时候,会依据数据库的两阶段过程,首先会向其他的 Server 发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。
10.4 集群中个服务器之间是怎样通信的
Leader 服务器会和每一个 Follower/Observer 服务器都建立 TCP 连接,同时为每个Follower/Observer 都创建一个叫做 LearnerHandler 的实体。LearnerHandler 主要负责 Leader 和Follower/Observer 之间的网络通讯,包括数据同步,请求转发和 proposal 提议的投票等。Leader 服务器保存了所有 Follower/Observer 的 LearnerHandler 。
10.5 分布式锁怎么实现的(与redis的分布式锁区别)
- 从技术上分析(区别)
- Redis 是nosql数据,主要特点缓存;
- Zookeeper是分布式协调工具,主要用于分布式解决方案
- 实现思路(区别)
- 获取锁
- Zookeeper
- 多个客户端,会在Zookeeper上创建同一个临时节点,因为Zookeeper节点命名路径保证唯一,不允许出现重复,只要谁能够先创建成功,谁能够获取到锁。
- Redis
- 多个客户端,会在Redis使用setnx命令创建相同的一个key,因为Redis的key保证唯一,不允许出现重复,只要谁能够先创建成功,谁能够获取到锁。
- Zookeeper
- 释放锁
- Zookeeper
- Zookeeper使用直接关闭临时节点session会话连接,因为临时节点生命周期与session会话绑定在一块,如果session会话连接关闭的话,该临时节点也会被删除。
这时候客户端使用事件监听,如果该临时节点被删除的话,重新进入盗获取锁的步骤。
- Zookeeper使用直接关闭临时节点session会话连接,因为临时节点生命周期与session会话绑定在一块,如果session会话连接关闭的话,该临时节点也会被删除。
- Redis
- Redis在释放锁的时候,为了确保是锁的一致性问题,在删除的redis 的key时候,需要判断同一个锁的id,才可以删除。
- Zookeeper
- 共同特征:如何解决死锁现象问题
- Zookeeper使用会话有效期方式解决死锁现象。
- Redis 是对key设置有效期解决死锁现象
- 获取锁
- 性能角度考虑
- 因为Redis是NoSQL数据库,相对比来说Redis比Zookeeper性能要好。
- 可靠性
- 从可靠性角度分析,Zookeeper可靠性比Redis更好。
因为Redis有效期不是很好控制,可能会产生有效期延迟,Zookeeper就不一样,因为Zookeeper临时节点先天性可控的有效期,所以相对来说Zookeeper比Redis更好
- 从可靠性角度分析,Zookeeper可靠性比Redis更好。
10.6 整体介绍和ZAB协议
-
(1)ZooKeeper分为服务器端(Server) 和客户端(Client),客户端可以连接到整个ZooKeeper服务的任意服务器上(除非 leaderServes 参数被显式设置, leader 不允许接受客户端连接)。
-
(2)客户端使用并维护一个 TCP 连接,通过这个连接发送请求、接受响应、获取观察的事件以及发送心跳。如果这个 TCP 连接中断,客户端将自动尝试连接到另外的 ZooKeeper服务器。客户端第一次连接到 ZooKeeper服务时,接受这个连接的 ZooKeeper服务器会为这个客户端建立一个会话。当这个客户端连接到另外的服务器时,这个会话会被新的服务器重新建立。
-
(3)上图中每一个Server代表一个安装Zookeeper服务的机器,即是整个提供Zookeeper服务的集群(或者是由伪集群组成);
-
(4)组成ZooKeeper服务的服务器必须彼此了解。它们维护一个内存中的状态图像,以及持久存储中的事务日志和快照, 只要大多数服务器可用,ZooKeeper服务就可用;
-
(5)ZooKeeper 启动时,将从实例中选举一个 leader,Leader 负责处理数据更新等操作,一个更新操作成功的标志是当且仅当大多数Server在内存中成功修改数据。每个Server 在内存中存储了一份数据。
-
(6)Zookeeper是可以集群复制的,集群间通过Zab协议(Zookeeper Atomic Broadcast)来保持数据的一致性;
-
(7)Zab协议包含两个阶段:leader election阶段和Atomic Brodcast阶段。
-
a) 集群中将选举出一个leader,其他的机器则称为follower,所有的写操作都被传送给leader,并通过brodcast将所有的更新告诉给follower。
-
b) 当leader崩溃或者leader失去大多数的follower时,需要重新选举出一个新的leader,让所有的服务器都恢复到一个正确的状态。
-
c) 当leader被选举出来,且大多数服务器完成了 和leader的状态同步后,leadder election 的过程就结束了,就将会进入到Atomic brodcast的过程。
-
d) Atomic Brodcast同步leader和follower之间的信息,保证leader和follower具有形同的系统状态。
-
10.7 节点ZNode和相关属性
- Znode两种类型
- 持久的(persistent):客户端和服务器端断开连接后,创建的节点不删除(默认)。
- 短暂的(ephemeral):客户端和服务器端断开连接后,创建的节点自己删除。
- Znode的四种形式 :
-
持久化目录节点(PERSISTENT)
客户端与Zookeeper断开连接后,该节点依旧存在 -
持久化顺序编号目录节点(PERSISTENT_SEQUENTIAL)
客户端与Zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号: -
临时目录节点(EPHEMERAL)
客户端与Zookeeper断开连接后,该节点被删除 -
临时顺序编号目录节点(EPHEMERAL_SEQUENTIAL)
客户端与Zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号
-
注意:
- 创建ZNode时设置顺序标识,ZNode名称后会附加一个值,顺序号是一个单调递增的计数器,由父节点维护;
- 一个znode节点不仅可以存储数据,还有一些其他特别的属性。
10.8 监听器的原理
- 创建一个Main()线程。
- 在Main()线程中创建两个线程,一个负责网络连接通信(connect),一个负责监听(listener)。
- 通过connect线程将注册的监听事件发送给Zookeeper。
- 将注册的监听事件添加到Zookeeper的注册监听器列表中。
- Zookeeper监听到有数据或路径发生变化时,把这条消息发送给Listener线程。
- Listener线程内部调用process()方法
10.9 假死&脑裂
- 假死:由于心跳超时(网络原因导致的)认为leader死了,但其实leader还存活着;
- 脑裂:由于假死会发起新的leader选举,选举出一个新的leader,但旧的leader网络又通了,导致出现了两个leader ,有的客户端连接到老的leader,而有的客户端则连接到新的leader。
要解决Split-Brain脑裂的问题,一般有下面几种种方法:
-
Quorums (法定人数) 方式
比如3个节点的集群,Quorums = 2, 也就是说集群可以容忍1个节点失效,这时候还能选举出1个lead,集群还可用。
比如4个节点的集群,它的Quorums = 3,Quorums要超过3,相当于集群的容忍度还是1,如果2个节点失效,那么整个集群还是无效的。
这是zookeeper防止"脑裂"默认采用的方法。 -
Redundant communications (冗余通信)方式
集群中采用多种通信方式,防止一种通信方式失效导致集群中的节点无法通信。 -
Fencing (共享资源) 方式
比如能看到共享资源就表示在集群中,能够获得共享资源的锁的就是Leader,看不到共享资源的,就不在集群中。
要想避免zookeeper"脑裂"情况其实也很简单,follower节点切换的时候不在检查到老的leader节点出现问题后马上切换,而是在休眠一段足够的时间,确保老的leader已经获知变更并且做了相关的shutdown清理工作了然后再注册成为master就能避免这类问题了,这个休眠时间一般定义为与zookeeper定义的超时时间就够了,但是这段时间内系统可能是不可用的,但是相对于数据不一致的后果来说还是值得的。
ZooKeeper默认采用了Quorums这种方式来防止"脑裂"现象。即只有集群中超过半数节点投票才能选举出Leader。
这样的方式可以确保leader的唯一性,要么选出唯一的一个leader,要么选举失败。
在zookeeper中Quorums作用如下:集群中最少的节点数用来选举leader保证集群可用。
通知客户端数据已经安全保存前集群中最少数量的节点数已经保存了该数据。
一旦这些节点保存了该数据,客户端将被通知已经安全保存了,可以继续其他任务。而集群中剩余的节点将会最终也保存了该数据。
假设某个leader假死,其余的followers选举出了一个新的leader。
这时,旧的leader复活并且仍然认为自己是leader,这个时候它向其他followers发出写请求也是会被拒绝的。
因为每当新leader产生时,会生成一个epoch标号(标识当前属于那个leader的统治时期),这个epoch是递增的,followers如果确认了新的leader存在,知道其epoch,就会拒绝epoch小于现任leader epoch的所有请求。
那有没有follower不知道新的leader存在呢,有可能,但肯定不是大多数,否则新leader无法产生。
Zookeeper的写也遵循quorum机制,因此,得不到大多数支持的写是无效的,旧leader即使各种认为自己是leader,依然没有什么作用。zookeeper除了可以采用上面默认的Quorums方式来避免出现"脑裂",
10.10 ZooKeeper 的持久化机制
- SnapShot 快照,记录内存中的全量数据
- TxnLog 增量事务日志,记录每一条增删改记录(查不是事务日志,不会引起数据变化)
快照的缺点,文件太大,而且快照文件不会是最新的数据;
增量事务日志的缺点,运行时间了,日志太多了,加载太慢。
10.11 ZooKeeper 负载均衡和 Nginx 负载均衡有什么区别?
- ZooKeeper:
- 不存在单点问题,zab 机制保证单点故障可重新选举一个 Leader
- 只负责服务的注册与发现,不负责转发,减少一次数据交换(消费方与服务方直接通信)
- 需要自己实现相应的负载均衡算法
- Nginx:
- 存在单点问题,单点负载高数据量大,需要通过 KeepAlived 辅助实现高可用
- 每次负载,都充当一次中间人转发角色,本身是个反向代理服务器
- 自带负载均衡算法
10.12 支持动态添加机器吗?
其实就是水平扩容了,Zookeeper 在这方面不太好。
两种方式:
-
全部重启:关闭所有 Zookeeper 服务,修改配置之后启动。不影响之前客户端的会话。
-
逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常
用的方式。
注意: 3.5 版本开始支持动态扩容。
10.13 Zookeeper与Eureka区别
都可以作为注册中心的Zookeeper和Eureka,想要理解两种注册中心的区别,首先要理解CAP理论。
CPA理论:
- C :Consistency(一致性):数据一致更新,所有数据变动都是同步的。
- A :Availability(可用性):好的相应性能。
- P :Partition tolerance(分区容忍性):可靠性。
一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性在分布式系统中是必须要保证的,因此我们只能在A和C之间权衡。故在此Zookeeper保证的是CP,而Eureka则保证的是AP
-
Zookeeper
当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,单不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。
但是Zookeeper会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。
问题在于,选举leader的时间太长,30s~120s,并且选举期间整个Zookeeper集群都是不可用的,这就导致在选举期间注册服务瘫痪。
在云部署的环境下,因网络问题是得Zookeeper集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。 -
Eureka
Eureka看明白了这点,因此在设计师就有限保证可用性;
Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册时如果发现连接失败,会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。
除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:- 1、Eureka不再从注册列表中溢出因为长时间没有收到心跳而应该过期的服务。
- 2、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其他节点上(即保证当前节点依然可用)。
- 3、当网络稳定是,当前实例新的注册信息会被同步到其他节点中。
因此,Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪