介绍
什么是zookeeper
首先看官网介绍:
ZooKeeper: A Distributed Coordination Service for Distributed Applications
Zookeeper是一个开源的分布式协调服务,由雅虎公司创建,由于最初雅虎公司的内部研究小组的项目大多以动物的名字命名,所以后来就以Zookeeper(动物管理员)来命名了,使用 Java 所编写。
简单来说 他是个数据库,文件存储系统(树状),并且有监听通知机制(观察者模式)
他的目标是可以提供高性能、高可用和顺序访问控制的能力,同时也是为了解决分布式环境下数据一致性的问题。
- ZooKeeper主要服务于分布式系统,可以用ZooKeeper来做:统一配置管理、统一命名服务、分布式锁、集群管理。
- 使用分布式系统就无法避免对节点管理的问题(需要实时感知节点的状态、对节点进行统一管理等等),而由于这些问题处理起来可能相对麻烦和提高了系统的复杂性,ZooKeeper作为一个能够通用解决这些问题的中间件就应运而生了。
应用场景
- 分布式锁
- 分布式微服务注册中心:服务发现与注册,在微服务架构中,服务提供者将地址信息注册到 ZooKeeper 节点,消费者通过监听节点变化动态获取可用服务列表
- 统一配置管理 通过创建持久化节点存储全局配置(如数据库连接信息),利用 Watcher 机制实现配置动态更新。当配置变更时,客户端通过“推拉结合”模式自动同步新配置。如Kafka。而如果你自己编写代码去做这件事 就很麻烦
- 集群管理与 Master 选举
- 集群管理 临时节点掉线自动失联
- Master选举 利用Zookeeper节点的全局唯一性,同时只有一个客户端能够创建成功的特点,可以作为Master选举使用,创建成功的则作为Master。
- 抢占模式:通过创建临时主节点实现快速选举,节点宕机后自动释放触发其他节点竞争。
- 顺序节点模式:利用临时有序节点的序号最小原则选举 Master,确保高可用性(如 HBase 集群)HBase
- 负载均衡:结合服务发现动态分配请求,根据节点状态选择最优服务实例。
- 分布式命名服务,利用节点路径唯一性为分布式资源分配全局唯一标识(如主机名、服务地址)。还有数据库分库分表后的唯一id主键命名服务。
特点
zookeeper的设计目标
zookeeper致力于为分布式应用提供一个高性能,高可用,具有严格顺序访问控制能力的分布式协调服务。
1、高性能
zookeeper将全量数据存储在内存中,并直接服务与客户端的所有非事务请求,尤其适合用于以读为主的应用场景。
2、高可用
zookeeper一般以集群的范式对外提供服务,一般3-5台机器就可以组成一个可用的zookeeper集群,每一台机器都会在内存中维护当前的服务器状态,并且每台机器之间都相互保持着通信。只要集群中超过一半的机器都在工作,那么这个集群就能够正常对外服务;
zookeeper天生适合集群部署,但是你单机部署一台也是可以的,只不过只能用部分功能。
集群部署推荐至少3节点且为奇数个(容忍1节点故障)(大于三个是因为必须过半才能选举出leader)
3、严格访问数据
对于客户端的每一个更新请求,Zookeeper都会分配一个全局唯一的递增编号,这个编号反映了所有事物操作的先后顺序。
为什么ZooKeeper能干这么多?
ZooKeeper的数据结构,跟Unix文件系统非常类似,可以看做是一颗树,每个节点叫做ZNode。每一个节点可以通过路径来标识,结构图如下:
那ZooKeeper这颗"树"有什么特点呢??ZooKeeper的节点我们称之为Znode,Znode分为两种类型:
-
短暂/临时(Ephemeral):当客户端和服务端断开连接后,所创建的Znode(节点)会自动删除
-
持久(Persistent):当客户端和服务端断开连接后,所创建的Znode(节点)不会删除
ZooKeeper和Redis一样,也是C/S结构(分成客户端和服务端)
Zookeeper中数据存储于内存之中,这个数据节点就叫做Znode
- znode 可以有子节点目录,并且每个 znode 可以存储数据
- znode 是有版本和版本号的,每个 znode 中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据
- znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端
- znode也可以像linux的文件那样进行权限的控制
节点怎么创建?-示例方便后续理解
我特么,这样问的么?可是我面试只看了分布式锁,我得好好想想!!!
还好我之前在自己的服务器搭建了一个zk的集群,我刚好跟大家回忆一波。
#首先使用docker安装 然后docker exec -it zookeeper zkCli.sh 进入zookeeper的cli控制台
create /test a // 创建永久节点 路径在根目录下叫test(就像一个文件) 值为a
create -e /test/tmp b // 创建临时节点 退出后,重新连接,创建的所有临时节点都没了
create -e /test/tmp c #Node already exists: /test/tmp会报错
get /test #输出a
[zk: localhost:2181(CONNECTED) 7] ls /
[test, zookeeper] #zookeeper是默认存在的节点
[zk: localhost:2181(CONNECTED) 8] ls /test
[tmp]
create -s /test // 创建顺序节点
//临时顺序节点呢?我想聪明的老公都会抢答了
create -e -s /test // 创建临时顺序节点
监听器
常见的监听场景有以下两项:
- 监听Znode节点的数据变化
- 监听子节点的增减变化
Zookeeper可以提供分布式数据的发布/订阅功能,依赖的就是Wather监听机制。
和redis那个类似
客户端可以向服务端注册Wather监听,同时将Watcher对象保存到客户端的Watch管理器中。服务端的指定事件触发之后,就会向客户端发送一个事件通知。而不必轮询。
他有几个特性:
- 一次性:一旦一个Watche触发之后,Zookeeper就会将它从存储中移除
- 客户端串行:客户端的Wather回调处理是串行同步的过程,不要因为一个Wather的逻辑阻塞整个客户端
- 轻量:Wather通知的单位是WathedEvent,只包含通知状态、事件类型和节点路径,不包含具体的事件内容,具体的时间内容需要客户端主动去重新获取数据
主要流程如下:
- 客户端向服务端注册Wather监听
- 保存Wather对象到客户端本地的WatherManager中
- 服务端Wather事件触发后,客户端收到服务端通知,从WatherManager中取出对应Wather对象执行回调逻辑
注意和redis的watch的区别 redis的仅能用于事务 而且必须是其他客户端的修改 这个key自身的过期是不算的
会话Session
会话自然就是指Zookeeper客户端和服务端之间的通信,他们使用TCP长连接的方式保持通信,通常,肯定会有心跳检测的机制,同时他可以接受来自服务器的Watch事件通知。
权限控制ACL
Zookeeper使用ACL来进行权限的控制,包含以下5种:
CREATE,创建子节点权限
DELETE,删除子节点权限
READ,获取节点数据和子节点列表权限
WRITE,更新节点权限
ADMIN,设置节点ACL权限
所以,Zookeeper通过集群的方式来做到高可用,通过内存数据节点Znode来达到高性能,但是存储的数据量不能太大,通常适用于读多写少的场景。
ZooKeeper作为“文件系统”怎么实现这些应用场景?
下面我们来看看用ZooKeeper怎么来做:统一配置管理、统一命名服务、分布式锁、集群管理。
统一配置管理
比如我们现在有三个系统A、B、C,他们有三份配置,分别是ASystem.yml、BSystem.yml、CSystem.yml,然后,这三份配置又非常类似,很多的配置项几乎都一样。
此时,如果我们要改变其中一份配置项的信息,很可能其他两份都要改。并且,改变了配置项的信息很可能就要重启系统
于是,我们希望把ASystem.yml、BSystem.yml、CSystem.yml相同的配置项抽取出来成一份公用的配置common.yml,并且即便common.yml改了,也不需要系统A、B、C重启。
做法:我们可以将common.yml这份配置放在ZooKeeper的Znode节点中,系统A、B、C监听着这个Znode节点有无变更,如果变更了,及时响应。
统一命名服务
统一命名服务的理解其实跟域名一样,是我们为这某一部分的资源给它取一个名字,别人通过这个名字就可以拿到对应的资源。
比如说,现在我有一个域名www.java3y.com,但我这个域名下有多台机器:
192.168.1.1
192.168.1.2
192.168.1.3
192.168.1.4
别人访问www.java3y.com即可访问到我的机器,而不是通过IP去访问。
分布式锁
我们可以使用ZooKeeper来实现分布式锁,那是怎么做的呢??下面来看看:
系统A、B、C都去访问/locks节点
访问的时候会创建带顺序号的临时/短暂(EPHEMERAL_SEQUENTIAL)节点,比如,系统A创建了id_000000节点,系统B创建了id_000002节点,系统C创建了id_000001节点。
接着,拿到/locks节点下的所有子节点(id_000000,id_000001,id_000002),判断自己创建的是不是最小的那个节点
-
如果是,则拿到锁。
执行完操作后,把创建的节点给删掉,释放锁: -
如果不是,则监听比自己要小1的节点变化
举个例子:
-
系统A拿到/locks节点下的所有子节点,经过比较,发现自己(id_000000),是所有子节点最小的。所以得到锁
-
系统B拿到/locks节点下的所有子节点,经过比较,发现自己(id_000002),不是所有子节点最小的。所以监听比自己小1的节点id_000001的状态
-
系统C拿到/locks节点下的所有子节点,经过比较,发现自己(id_000001),不是所有子节点最小的。所以监听比自己小1的节点id_000000的状态
-
……
-
等到系统A执行完操作以后,将自己创建的节点删除(id_000000)。通过监听,系统C发现id_000000节点已经删除了,发现自己已经是最小的节点了,于是顺利拿到锁
-
….系统B如上
具体实现 看另一篇文章
集群状态的监听、注册中心
经过上面几个例子,我相信大家也很容易想到ZooKeeper是怎么"感知"节点的动态新增或者删除的了。
还是以我们三个系统A、B、C为例,在ZooKeeper中创建临时节点即可:
只要系统A挂了,那/groupMember/A这个节点就会删除,通过监听groupMember下的子节点,系统B和C就能够感知到系统A已经挂了。(新增也是同理)
注册中心要解决什么问题?
- 服务注册:实例上线时登记自己的地址(如192.168.1.1:8080)
- 服务发现:消费者快速找到可用服务列表
- 健康监测:自动剔除故障节点
- 配置管理:统一管理服务元数据(如权重、版本)
可以利⽤Zookeeper的临时顺序节点和watch机制来实现注册中⼼的⾃动注册和发现,另外Zookeeper中的 数据都是存在内存中的,并且Zookeeper底层采⽤了nio,多线程模型,所以Zookeeper的性能也是⽐较⾼的,以及用了zab协议保证一致性。所以可以⽤来作为注册中⼼。但是如果考虑到注册中⼼应该是注册可⽤性的话,那么Zookeeper 则不太合适,因为Zookeeper是CP的,它注重的是⼀致性,所以集群数据不⼀致时,集群将不可⽤,所以⽤Redis、Eureka、Nacos来作为注册中⼼将更合适。
集群leader的选举
除了能够感知节点的上下线变化,ZooKeeper还可以实现动态选举Master的功能。(如果集群是主从架构模式下)
原理也很简单,如果想要实现动态选举Master的功能,Znode节点的类型是带顺序号的临时节点(EPHEMERAL_SEQUENTIAL)就好了。
Zookeeper会每次选举最小编号的作为Master,如果Master挂了,自然对应的Znode节点就会删除。然后让新的最小编号作为Master,这样就可以实现动态选举的功能了。
一致性协议——ZAB——数据如何写?崩溃如何恢复?
ZAB(ZooKeeper Atomic Broadcast)协议是专为ZooKeeper设计的分布式一致性协议,核心目标是解决分布式系统中的数据一致性问题。它通过原子广播和崩溃恢复机制,确保集群中所有节点的数据副本保持一致,即使在部分节点故障时也能快速恢复。
概念
首先,Zookeeper集群中有几个关键的概念,Leader、Follower和Observer,Zookeeper中通常只有Leader节点可以写入,Follower和Observer都只是负责读,但是Follower会参与节点的选举和过半写成功,Observer则不会,他只是单纯的提供读取数据的功能。
通常这样设置的话,是为了避免太多的从节点参与过半写(在集群部署下,leader将事务请求(例如create指令)发送给大多数(一半以上)的follower且成功执行后,则算作该事务请求成功执行。)的过程,导致影响性能,这样Zookeeper只要使用一个几台机器的小集群就可以实现高性能了,如果要横向扩展的话,只需要增加Observer节点即可。
Zookeeper建议集群节点个数为奇数,只要超过一半的机器能够正常提供服务,那么整个集群都是可用的状态。
集群角色
- Leader:同一时间集群总只允许有一个Leader,提供对客户端的读写功能,负责将数据同步至各个节点;
- Follower:提供对客户端读功能,写请求则转发给Leader处理,当Leader崩溃失联之后参与Leader选举;
- Observer:与Follower不同的是但不参与Leader选举。
服务状态
- LOOKING:当节点认为群集中没有Leader,服务器会进入LOOKING状态,目的是为了查找或者选举Leader;
- FOLLOWING:follower角色;
- LEADING:leader角色;
- OBSERVING:observer角色;
可以知道Zookeeper是通过自身的状态来区分自己所属的角色,来执行自己应该的任务。
ZAB状态:Zookeeper还给ZAB定义的4中状态,反应Zookeeper从选举到对外提供服务的过程中的四个步骤。状态枚举定义:
public enum ZabState {
ELECTION,
DISCOVERY,
SYNCHRONIZATION,
BROADCAST
}
- ELECTION: 集群进入选举状态,此过程会选出一个节点作为leader角色;
- DISCOVERY:连接上leader,响应leader心跳,并且检测leader的角色是否更改,通过此步骤之后选举出的leader才能执行真正职务;
- SYNCHRONIZATION:整个集群都确认leader之后,将会把leader的数据同步到各个节点,保证整个集群的数据一致性;
- BROADCAST:过渡到广播状态,集群开始对外提供服务。
ZXID
Zxid是极为重要的概念,它是一个long型(64位)整数,分为两部分:纪元(epoch)部分和计数器(counter)部分,是一个全局有序的数字。
epoch代表当前集群所属的"朝代",leader的选举就类似一个朝代的更替,你前朝的剑不能斩本朝的官,用epoch代表当前命令的有效性,counter是一个递增的数字。
集群数据同步流程——原子广播(全局有序广播)与两阶段写(半同步复制)
- 两阶段提交改进:Leader将客户端写请求转化为事务Proposal,广播给所有Follower,收到半数以上ACK后提交事务(类似2PC但只需过半确认)。
- 异步解耦:Leader与Follower间通过队列通信,避免同步阻塞,提升性能。
- 全局有序性:每个事务分配唯一ZXID(全局递增ID),保证顺序执行。
-
leader节点统一处理写请求
在Zookeeper集群中,只有leader节点能够处理写操作,其他的follower节点都只能处理读操作,但其并不是不能接受写请求,当接收到写操作的请求时,follower节点会讲这个请求转发给leader节点来处理。 -
生成并广播提案
Leader节点在接受到写请求后,会生成将写请求先转化成提案(或者事务Proposal),并赋予zxid,然后将这份提案广播给所有的Follower节点。 -
Follower节点确认提案
Follower在接受到Leader节点的提案后,会确认当前提案的zxid是不是正确的。如果正确,则会保存当前提案的zxid,follower节点将收到的事务请求加入到历史队列(history queue)中,并且执行提案的事务操作,但不提交,并返回确认消息ACK,等待Leader再次发送消息时,提交事务更改。
在ZooKeeper中,每个写操作(提案)都会被分配一个递增的事务ID,称为zxid。这个zxid用来标识提案的顺序,确保所有节点按照相同的顺序应用这些操作,以维持数据的一致性,而Follower就根据zxid来确认当前提案是否是期待的下一次提案,已确保事务执行的正确顺序,防止因写操作顺序不一致导致数据差异,具体规则如下:-
接收提案:当Follower节点收到一个提案时,它首先会检查这个提案的zxid。
-
处理过期提案:如果这个提案的zxid比Follower当前已经处理的最新zxid要小,说明这个提案是过期的,可能由于网络延迟或其他原因延迟到达。为了防止数据回滚(即不正确地应用旧的、更早的数据),Follower会直接忽略这个提案,不会保存或执行它。
-
处理未来提案:如果Follower收到的提案zxid比它当前期望的zxid要大,这意味着一些提案在传输过程中丢失了或尚未到达。为了保持数据一致性,Follower会先保存这个提案,但不会立即执行。它会等待缺失的提案到达,并在提案顺序完整时,按顺序执行所有提案。
-
读请求处理:在等待缺失提案的过程中,Follower可能暂时无法提供最新的数据。为了避免返回不一致的数据,Follower会将接收到的读请求转发给Leader节点。Leader拥有最新的提交状态,因此能够返回最准确的数据。
-
-
Leader节点返回成功消息
当Leader节点在接受到一半以上的Follower节点的确认消息后,其就认为当前集群已经可以同步所有写操作,Leader就会通知所有从节点本次提案通过,从节点接收到这个消息后就会提交提案中的事务操作的结果,并且Leader此时会返回给客户端操作成功的响应。
zab在广播状态中保证以下特征
- 可靠传递: 如果消息m由一台服务器传递,那么它必须被发送到所有节点
- 有序性 有序性是zab协议必须要保证的一个很重要的属性,因为zookeeper是以类似目录结构的数据结构存储数据的,必须要求命名的有序性。
- 全局有序: 如果一个消息a在消息b之前被一台服务器交付,那么所有服务器都交付了a和b,并且a先于b。
- 因果有序: 如果消息a在因果上先于消息b并且二者都被交付,那么a必须排在b之前。
比如一个命名a创建路径为/test,然后命名b创建路径为/test/123,如果不能保证有序性b命名在a之前,b命令会因为父节点不存在而创建失败。
有以上流程可知,zookeeper通过二阶段提交来保证集群中数据的一致性与高可用,因为只需要收到过半的ACK就可以提交事务,所以zookeeper的数据并不是强一致性。
zab协议的有序性保证是通过几个方面来体现的,
第一是,服务之前用TCP协议进行通讯,保证在网络传输中的有序性;
第二,节点之前都维护了一个FIFO的队列,保证全局有序性;
第三,通过全局递增的zxid保证因果有序性。
崩溃恢复与初始选举
下面开始介绍zab协议是怎么支持leader选举的。
进行leader有三个问题,什么时候进行?选举规则?选择流程?
下面我会一一解答这三个问题:
-
选举发生的时机Leader发生选举有两个时机,一个是服务启动的时候当整个集群都没有leader节点会进入选举状态,如果leader已经存在就会告诉该节点leader的信息,自己连接上leader,整个集群不用进入选举状态。
还有一个就是在服务运行中,可能会出现各种情况,服务宕机、断电、网络延迟很高的时候leader都不能再对外提供服务了,所有当其他几点通过心跳检测到leader失联之后,集群也会进入选举状态。 -
选举规则进入投票选举流程,怎么才能选举出leader?或者说按照什么规则来让其他节点都能选举你当leader。
zab协议是按照几个比较规则来进行投票的筛选,如果你的票比我更好,就修改自身的投票信息,改投你当leader。
下面代码是zookeeper投票比较规则:
/*
* We return true if one of the following three cases hold:
* 1- New epoch is higher
* 2- New epoch is the same as current epoch, but new zxid is higher
* 3- New epoch is the same as current epoch, new zxid is the same
* as current zxid, but server id is higher.
*/
return ((newEpoch > curEpoch)
|| ((newEpoch == curEpoch)
&& ((newZxid > curZxid)
|| ((newZxid == curZxid)
&& (newId > curId)))));
当其他节点的纪元比自身高投它,如果纪元相同比较自身的zxid的大小,选举zxid大的节点,这里的zxid代表节点所提交事务最大的id,zxid越大代表该节点的数据越完整。
最后如果epoch和zxid都相等,则比较服务的serverId,这个Id是配置zookeeper集群所配置的,所以我们配置zookeeper集群的时候可以把服务性能更高的集群的serverId配置大些,让性能好的机器担任leader角色。
- 选举流程
时机和规则都有了,下面就是leader的选举流程
所有节点第一票先选举自己当leader,将投票信息广播出去;
从队列中接受投票信息;
按照规则判断是否需要更改投票信息,将更改后的投票信息再次广播出去;
判断是否有超过一半的投票选举同一个节点,如果是选举结束根据投票结果设置自己的服务状态,选举结束,否则继续进入投票流程。
举例
上图来自《ZooKeeper:分布式过程协同技术详解》,整体流程还是比较简单,这里就不具体分析了。
状态流转
前面介绍了zookeeper服务状态有四种,ZAB状态也有四种。这里就简单介绍一个他们之间的状态流转,更能加深对zab协议在zookeeper工作流程中的作用。
服务在启动或者和leader失联之后服务状态转为LOOKING;
如果leader不存在选举leader,如果存在直接连接leader,此时zab协议状态为ELECTION;
如果有超过半数的投票选择同一台server,则leader选举结束,被选举为leader的server服务状态为LEADING,其他server服务状态为FOLLOWING/OBSERVING;
所有server连接上leader,此时zab协议状态为DISCOVERY;
leader同步数据给learner,使各个从节点数据和leader保持一致,此时zab协议状态为SYNCHRONIZATION;
同步超过一半的server之后,集群对外提供服务,此时zab状态为BROADCAST。
可以知道整个zookeeper服务的工作流程类似一个状态机的转换,而zab协议就是驱动服务状态流转的关键,理解了zab就理解了zookeeper工作的关键原理
选举之后又是怎样进行数据同步的?
那实际上Zookeeper在选举之后,Follower和Observer(统称为Learner)就会去向Leader注册,然后就会开始数据同步的过程。
数据同步包含3个主要值和4种形式。
- PeerLastZxid:Learner服务器最后处理的ZXID
- minCommittedLog:Leader提议缓存队列中最小ZXID
- maxCommittedLog:Leader提议缓存队列中最大ZXID
直接差异化同步 DIFF同步
如果PeerLastZxid在minCommittedLog和maxCommittedLog之间,那么则说明Learner服务器还没有完全同步最新的数据。
首先Leader向Learner发送DIFF指令,代表开始差异化同步,然后把差异数据(从PeerLastZxid到maxCommittedLog之间的数据)提议proposal发送给Learner
发送完成之后发送一个NEWLEADER命令给Learner,同时Learner返回ACK表示已经完成了同步
接着等待集群中过半的Learner响应了ACK之后,就发送一个UPTODATE命令,Learner返回ACK,同步流程结束
先回滚再差异化同步 TRUNC+DIFF同步
这个设置针对的是一个异常的场景。
如果Leader刚生成一个proposal,还没有来得及发送出去,此时Leader宕机,重新选举之后作为Follower,但是新的Leader没有这个proposal数据。
举个栗子:
假设现在的Leader是A,minCommittedLog=1,maxCommittedLog=3,刚好生成的一个proposal的ZXID=4,然后挂了。
重新选举出来的Leader是B,B之后又处理了2个提议,然后minCommittedLog=1,maxCommittedLog=5。
这时候A的PeerLastZxid=4,在(1,5)之间。
那么这一条只存在于A的提议怎么处理?
A要进行事务回滚,相当于抛弃这条数据,并且回滚到最接近于PeerLastZxid的事务,对于A来说,也就是PeerLastZxid=3。
流程和DIFF一致,只是会先发送一个TRUNC命令,然后再执行差异化DIFF同步。
仅回滚同步 TRUNC同步
针对PeerLastZxid大于maxCommittedLog的场景,流程和上述一致,事务将会被回滚到maxCommittedLog的记录。
这个其实就更简单了,也就是你可以认为TRUNC+DIFF中的例子,新的Leader B没有处理提议,所以B中minCommittedLog=1,maxCommittedLog=3。
所以A的PeerLastZxid=4就会大于maxCommittedLog了,也就是A只需要回滚就行了,不需要执行差异化同步DIFF了。
全量同步 SNAP同步
适用于两个场景:
- PeerLastZxid小于minCommittedLog
- Leader服务器上没有提议缓存队列,并且PeerLastZxid不等于Leader的最大ZXID
这两种场景下,Leader将会发送SNAP命令,把全量的数据都发送给Learner进行同步。
持久化
ZooKeeper的持久化机制确保了数据的高可用性和一致性,即使在服务器重启或崩溃的情况下,数据也不会丢失。ZooKeeper通过两种主要的持久化机制来实现这一点:事务日志(Transaction Log)和快照(Snapshot)。
持久化机制的原理
如果作为注册中心,Zookeeper 和Eureka、Consul、Nacos有什么区别?
Nacos Eureka Consul Zookeeper
一致性协议 CP+AP AP CP CP
健康检查 TCP/HTTP/MYSQL/Client Beat Client Beat TCP/HTTP/gRPC/Cmd Keep Alive
负载均衡策略 权重/ metadata/Selector Ribbon Fabio —
雪崩保护 有 有 无 无
自动注销实例 支持 支持 不支持 支持
访问协议 HTTP/DNS HTTP HTTP/DNS TCP
监听支持 支持 支持 支持 支持
多数据中心 支持 支持 支持 不支持
跨注册中心同步 支持 不支持 支持 不支持
SpringCloud集成 支持 支持 支持 不支持
Dubbo集成 支持 不支持 不支持 支持
K8S集成 支持 不支持 支持 不支持