ZooKeeper & Nacos

作为注册中心对比

方面 ZooKeeper作为注册中心 Nacos(服务注册发现,配合负载均衡)
数据一致性角色 内部有Leader/Follower,用于保证注册数据的一致性 内部有Raft协议选举Leader,或使用Distro协议,目的相同。
服务节点角色 注册的服务实例是对等的 注册的服务实例是对等的
服务发现读请求 客户端可从任何ZK节点(通常是Follower)读取服务列表。 客户端可从任何Nacos节点读取服务列表。
流量路由决策 在客户端通过负载均衡器做出。 在客户端通过负载均衡器(如Ribbon)做出。
业务流量路径 直接 从调用者到被调用的服务实例,不经过ZK 直接 从调用者到被调用的服务实例,不经过Nacos

Zookeeper数据一致性(CP)

实现机制

  1. ZAB协议 :ZooKeeper使用ZAB(ZooKeeper Atomic Broadcast)协议来保证集群中各个节点状态的强一致性。这个协议与Paxos算法类似,能确保 写操作在所有节点上以相同的顺序被提交。

  2. Leader写 :所有写请求都必须由Leader节点处理,并由Leader将更新广播给Follower节点。只有当超过半数的节点(Quorum)都确认写入后,这次写操作才会被提交,并向客户端返回成功。(Follower节点可以提供读服务)

  3. 健康检查:基于临时节点(Ephemeral Nodes)。客户端与ZooKeeper服务器维持一个会话(Session)。如果会话超时,则该客户端创建的所有临时节点会被自动删除。

在ZooKeeper的CP模型中,当发生网络分区时,为了保证数据的一致性,它会让少数派分区(无法形成Quorum)的节点不可用。对于服务注册中心来说,这意味着部分服务调用者可能会暂时无法获取服务列表,但获取到的列表一定是与主分区一致的。

问题:多数节点同意为啥保证了强一致性

多数节点同意并不代表所有节点同意,所以为啥ZAB保证了强一致性?

1. ZAB协议

ZAB协议的核心:两阶段提交 + 事务ID

ZAB协议的写操作(如你提到的set命令)并不是简单地"收到多数派确认就返回",它包含一个严谨的两阶段过程:

阶段一:Leader发起提案(Broadcast)

  1. Leader为这个写请求分配一个全局单调递增的事务ID

  2. Leader将这个提案(包含新的数据内容和ZXID)持久化到自己的本地磁盘

  3. Leader将提案发送给所有的Follower(包括你例子中的A, B, C)。

阶段二:Leader提交提案(Commit)

  1. Leader等待超过半数的Follower (包括自己)返回ACK确认。在你的三节点集群中,多数派是2,所以当Leader收到A的ACK时,加上自己,就已经满足了多数派(A + Leader = 2)。

  2. 关键点来了 :此时,Leader虽然满足了多数派,但它不会立即向客户端返回成功 。它还需要做一件事:向所有已经ACK的Follower (在这个例子里是A)发送一个 COMMIT 消息 。这个COMMIT消息的意思是:"我之前发给你的那个提案,现在可以正式生效了,把它应用到你的内存状态机里。"

  3. 只有当Leader自己也应用了这个提案,并且(在某些实现中)发送了COMMIT之后,它才会向客户端返回写操作成功的响应

2.读请求保证一致性

现在,如果一个读请求发到了C节点,会发生什么?

  1. Follower的自我认知 :在ZooKeeper中,Follower不能独立处理写请求,同时对于读请求,它也必须确保自己的数据不是过时的

  2. Sync机制 :为了处理读请求,Follower C首先需要与Leader进行一次 sync 操作。这个操作的目的就是将自己的状态与Leader同步到最新。

  3. C节点的行为

    • 当读请求到达C时,C会发现自己的ZXID(99)落后于它所知的Leader的ZXID。

    • C会拒绝直接提供这个可能过期的数据。

    • C会尝试与Leader同步。由于网络分区,这个同步请求会失败。

    • 因为同步失败,C会认为自己的数据不是最新的,进而会拒绝客户端的这个读请求 ,或者让客户端超时。最终,客户端的ZooKeeper客户端库会将连接重定向到一个健康的、数据最新的节点(比如A或B)

问题:读操作Follower节点的同步是怎样的?

Follower节点在提供读服务前,会通过一种机制(显式的sync或隐式的连接健康度检查)来评估自己的数据是否足够新。如果评估失败,它宁可拒绝服务也不会返回可能过期的数据,以此坚决捍卫CP特性。

Follower节点提供读服务时,需要判断其与Leader节点是否同步。这个"判断"过程有显式和隐式两种方式,并且根据ZooKeeper的版本和配置,其严格程度也有所不同。下面来详细拆解一下:

1. 显式同步:sync 操作

  • 流程

    1. 客户端向Follower发起一个读请求。

    2. 在Follower返回数据之前 ,它会先向Leader发送一个特殊的 sync 请求。

    3. Leader会阻塞这个sync请求,Leader 主动检查并推送 Follower 缺失的所有数据,主动帮助 Follower 的 ZXID 与自己保持一致。

    4. Leader回复Follower sync 完成。

    5. Follower确认自己的数据是最新的,然后才执行本地读操作,将结果返回给客户端。

  • 优点 :提供了线性一致性的读保证。客户端读到的数据一定是最新的,并且能看到之前所有已完成的写操作。

  • 缺点延迟高。每次读操作都可能需要一次与Leader的网络往返,增加了延迟,失去了在Follower上读操作降低负载的意义。

2. 隐式检查:会话与连接状态

这是更常见和默认的行为,它依赖于Follower与Leader之间的心跳和通信状态。

  • 流程

    1. Follower与Leader维持着一个心跳连接。通过这个连接,Follower不断地知道Leader的最新ZXID。

    2. 当客户端向Follower发起读请求时,Follower会进行一个本地的、快速的检查

      • 检查1:连接状态。我(Follower)和Leader的连接是否健康?如果我最近刚和Leader有过成功的心跳,说明我同步得很好。

      • 检查2:ZXID差距(逻辑上的) 。虽然Follower不会在每次读请求时都去精确比对ZXID,但它通过心跳和来自Leader的数据包,大致知道自己的数据是否滞后。如果它发现自己已经有一段时间没有收到Leader的消息,或者明确知道自己的ZXID远落后于Leader,它就会认为自己状态可疑。

  • 当Follower认为自己"落后"或"失联"时

    • 它会拒绝客户端的读请求

    • 它会关闭与客户端的会话,或者让客户端的请求超时。

    • 客户端的ZooKeeper库在收到错误或超时后,会自动重连到集群中的另一个节点(很可能是一个数据更新的Follower或Leader本身)。

Nacos的高可用(AP)

作为服务注册中心,服务的可用性注册中心的自身可用性至关重要。它优先保证在绝大多数情况下(包括网络分区时)服务都能被注册和发现,即使读到的信息可能不是最新的。

实现机制

  1. 自研协议(AP模式) :Nacos默认使用一种自研的、基于异步复制 的协议(Distro协议)。节点之间相互对等,服务实例向某个Nacos节点注册后,该节点会异步地将信息传播给其他节点。

  2. 客户端心跳 :服务实例定期向Nacos服务器发送心跳来维持注册状态。如果一个Nacos节点长时间收不到某服务实例的心跳,它会将该实例标记为不健康,但不会立即删除。这个信息也会异步地传播。

  3. 可切换的CP模式 :对于配置信息等需要强一致性的场景,Nacos支持切换到CP模式,使用Raft协议 来选举Leader并实现强一致性。但服务发现功能默认是AP的

    • 服务发现AP, 意思是说服务发现时,请求的当前Nacos节点并不会像Zookeeper中那样判断与主节点ZXID的同步性。

在网络分区下的表现

假设一个由3个节点(N1, N2, N3)组成的Nacos集群。

  • 发生网络分区,将N1和N2与N3隔开。

  • 此时,两个分区都无法感知到对方的存在 ,但它们都仍然认为自己可以提供服务

  • 服务实例A注册在N1上,服务实例B注册在N3上。

  • 连接到N1或N2的客户端,能看到服务A,但可能看不到服务B(或者看到B但标记为不健康)。

  • 连接到N3的客户端,能看到服务B,但可能看不到服务A。

  • 双方都仍然可以工作 ,都可以进行服务注册和发现,但看到的数据视图是不一致的

总结:在Nacos的AP模型中,当发生网络分区时,为了保证服务的可用性,它允许各个分区继续独立工作,但牺牲了数据的强一致性。你可能会读到旧数据或不完整的数据,但你的服务调用不会因为注册中心本身的问题而完全失败。

相关推荐
wanhengidc1 小时前
云手机中分布式存储的功能
运维·服务器·分布式·游戏·智能手机·云计算
TracyCoder1231 小时前
微服务注册中心基础(五):Zookeeper 适用场景
微服务·zookeeper·架构·注册中心
Serverless社区1 小时前
【本不该故障系列】告别资源“不确定性”,SAE如何破解刚性交付核心困境
阿里云·云原生·serverless
u***j3242 小时前
HarmonyOS分布式能力核心技术深度解析
分布式·华为·harmonyos
7***n752 小时前
HarmonyOS分布式数据管理
分布式·华为·harmonyos
TracyCoder1232 小时前
Dubbo+Zookeeper怎么实现的服务注册与发现
分布式·zookeeper·dubbo
G***E3165 小时前
PHP微服务通信消息队列实践
微服务·云原生·架构
TracyCoder1237 小时前
微服务注册中心基础(一):AP架构原理
微服务·云原生·架构·注册中心
C***u1768 小时前
分布式多卡训练(DDP)踩坑
分布式