【Nacos系列】服务发现:一致性实现

目录

一、服务发现模块核心机制

二、数据一致性实现

[1. 客户端与服务端之间的一致性 (最终一致性)](#1. 客户端与服务端之间的一致性 (最终一致性))

[2. 服务端节点之间的一致性 (分布式存储一致性)](#2. 服务端节点之间的一致性 (分布式存储一致性))

总结


下面详细介绍 Nacos 1.x 服务发现模块及其数据一致性实现(涵盖客户端-服务端、服务端节点间):

一、服务发现模块核心机制

Nacos 服务发现的核心是 ServiceManagerClient 交互:

  1. 服务注册 (Registration):
    • 客户端 (服务提供者) 启动时,通过 HTTP/gRPC 向 Nacos Server 发送注册请求,包含自身实例信息 (IP, Port, 元数据, 集群名, 分组等)。
    • Nacos Server 的 InstanceController 接收请求,调用 ServiceManager
    • ServiceManager 在内存 (ConcurrentHashMap<String, Service>) 中创建或找到对应的 Service 对象,将 Instance 添加到该 Service 的实例列表 (Cluster) 中。
    • 触发 ServiceChangeEvent 事件,通知订阅了该服务的客户端。
  1. 服务发现 (Discovery):
    • 客户端 (服务消费者) 启动时,通过 HTTP/gRPC 向 Nacos Server 查询指定服务名的所有健康实例列表。
    • Nacos Server 的 InstanceController 处理查询,ServiceManager 从内存中获取对应 Service 的实例列表,根据健康状态过滤后返回。
    • 客户端通常会缓存这份初始列表。
  1. 服务订阅与推送 (Subscription & Push):
    • 客户端在获取初始列表后,会向 Nacos Server 订阅该服务的变更。
    • Nacos Server 将订阅关系存储在内存 (ClientManager / SubscriberServiceV1Impl)。
    • 当服务的实例发生注册、注销、健康状态变更 时,ServiceManager 触发 ServiceChangeEvent
    • PushService 监听到事件,遍历该服务的所有订阅者 (客户端),通过 UDPgRPC 长连接 向客户端推送变更通知 (只包含变更的服务名)。
    • 客户端收到推送通知后,主动发起一次HTTP 查询 请求 (GET /nacos/v1/ns/instance/list) 获取该服务最新的全量实例列表,并更新本地缓存。
  1. 健康检查 (Health Check):
    • 客户端心跳 (Client Beat): 注册成功的客户端会定期 (默认 5 秒) 向 Nacos Server 发送心跳 (HTTP PUT /nacos/v1/ns/instance/beat) 证明自己存活。BeatReactor 处理心跳。
    • 服务端主动探测 (Server-Side Check): 如果客户端超过一定时间 (默认 15 秒) 未发送心跳,Nacos Server 的健康检查线程 (HealthCheckReactor) 会主动探测该实例 (TCP/HTTP/MYSQL/TTL)。探测失败则标记实例为 unhealthy 或直接删除。ClientBeatCheckTask 监控心跳超时。

二、数据一致性实现

1. 客户端与服务端之间的一致性 (最终一致性)

  • 核心目标: 确保客户端本地缓存的实例列表尽可能接近 Nacos Server 内存中的真实状态。
  • 实现机制:
    • 心跳维持租约 (Lease): 客户端心跳相当于续租。服务端认为最近心跳时间 + 超时时间内的实例是健康的。超时未续租的实例会被标记或删除。
    • 服务端主动健康检查: 作为心跳的兜底机制,确保即使客户端异常退出(无法发送注销请求),服务端也能探测到并清理无效实例。
    • 变更推送 + 主动查询: UDP/gRPC Push 通知及时性高 但可能丢失(尤其是UDP)。客户端收到通知后主动发起的 HTTP 查询是可靠的获取最新数据的保证。
    • 客户端定时轮询兜底: 即使推送完全失败,客户端也会定时 (默认 30 秒) 主动发起 HTTP 查询 (GET /nacos/v1/ns/instance/list) 来刷新本地缓存,确保最终一致。
  • 一致性模型: 最终一致性。从实例变更(注册/注销/健康状态变化)发生到所有订阅的客户端感知到变更,存在短暂延迟(通常在秒级)。推送的及时性和心跳/轮询的间隔决定了不一致窗口的大小。

2. 服务端节点之间的一致性 (分布式存储一致性)

  • 核心目标: 在 Nacos 集群部署时,确保所有节点内存中存储的同一服务的实例信息最终相同。
  • 实现机制 (Distro 协议 - AP 模式): Nacos 服务发现默认采用自研的 Distro 协议 ,这是一个 AP (Availability, Partition tolerance) 优先的、最终一致性的分布式协议。
    • 数据分片与责任节点: Distro 协议将集群中所有服务的实例数据虚拟分片 。每个 Nacos 节点被设计为负责一部分服务数据的"责任节点 "。责任分配基于一致性哈希 算法(如 VirtualNode),通常使用服务名(Service Name) + 集群名(Cluster Name) 作为哈希 Key。
    • 写操作流程 (注册/注销):
      • 当客户端向某个 Nacos 节点 (Node A) 发起注册/注销请求时:
        • 如果 Node A 是该服务数据的责任节点,则:
          1. 本地内存中执行实例的添加/删除/更新操作。
          2. 将操作写入本地磁盘文件 (data/protocol/) 进行持久化(用于重启恢复,不是主存储)。
          3. 触发 ServiceChangeEvent(引发后续的客户端推送)。
          4. 异步 地将此变更数据 通过 HTTP 请求批量复制 (DistroHttpAgent) 给集群中的所有其他节点 (Node B, Node C...)。
        • 如果 Node A 是非责任节点 ,它会将请求重定向 (HTTP 307)代理转发 给该服务数据的责任节点 (Node X)。由 Node X 执行上述责任节点的操作。
    • 读操作流程 (查询):
      • 客户端向任意节点 (Node Y) 发起查询请求。
      • Node Y 直接查询自己本地内存中存储的该服务实例数据并返回给客户端。
      • 关键点: 非责任节点 (Node Y) 本地存储的数据可能滞后 于责任节点 (Node X) 的数据,因为它依赖于 Node X 的异步复制。这是实现高可用 (任何节点都可读)和低延迟 (本地读)的代价,导致读取可能不是强一致的
    • 数据同步 (健康检查与修复):
      • 定时同步摘要 (Checksum): 每个节点定期 计算自己负责的所有服务的实例列表的校验和 (Checksum),并将这些摘要信息发送给集群中的其他节点。
      • 校验和比对: 节点收到其他节点的摘要信息后,会与自己计算的摘要进行比对。
      • 差异拉取 (Sync): 如果发现某个服务的校验和不匹配(表明数据不一致),节点会主动向持有该服务最新数据的节点(通常是责任节点)发起 HTTP 请求拉取该服务的全量实例数据 (GET /nacos/v1/ns/distro/datum) 来覆盖本地数据,完成修复。
      • 新节点加入/重启: 新加入的节点或重启恢复的节点,会主动向集群中其他节点拉取其负责的数据分片的全量数据 (GET /nacos/v1/ns/distro/datums) 进行初始化。
    • 健康探测: Distro 节点间通过轻量级的心跳互相探测可用性,用于判断节点是否存活,影响数据同步和重定向。
  • 一致性模型: 最终一致性 (Eventual Consistency) 。Distro 协议优先保证可用性 (A)分区容错性 (P)
    • 网络分区发生时,不同分区的节点仍然可以独立处理自己责任分片内的读写请求(可能导致数据冲突)。
    • 异步复制定时校验同步机制保证了在网络恢复后,数据最终会达成一致。
    • 无分区的正常情况下,数据复制延迟决定了节点间的不一致窗口(通常很小,毫秒到秒级)。
  • 与 CP 模式对比: Nacos 配置中心 模块支持基于 Raft 算法的 CP 模式(需要强一致性)。但服务发现 模块默认且主要 使用 AP 模式的 Distro 协议。这是由服务发现的场景特点决定的:服务实例频繁上下线,对可用性要求极高,短暂的数据不一致(如某个节点短暂显示一个刚下线的实例)通常是可以容忍的。用户可以通过 nacos.standalone=false + nacos.member.list 配置集群,并确保所有节点使用相同的 Distro 实现(默认内置)。

总结

  • 服务发现流程: 围绕 ServiceManager 进行实例存储,通过注册、心跳、订阅、推送+查询、主动健康检查实现动态管理。
  • 客户端-服务端一致性 (最终一致): 依赖心跳租约服务端健康检查兜底变更推送触发主动查询客户端定时轮询兜底 共同保证客户端缓存最终与服务端状态一致。
  • 服务端节点间一致性 (最终一致 - AP): 基于 Distro 协议 。通过数据分片与责任节点写请求路由/转发责任节点本地处理+异步复制任意节点本地读取定时校验和比对+差异数据拉取 等机制,在保证高可用和分区容错的前提下,实现数据的最终一致性。这是 Nacos 服务发现高可用架构的核心。
相关推荐
Byte Beat13 小时前
springCloudAlibaba最新版本2023.0.3.2 与nacos3.0的连接不上问题记录
java·spring cloud·nacos
大数据张老师1 天前
服务发现与动态负载均衡的结合
运维·服务发现·负载均衡
workflower2 天前
敏捷开发项目的需求管理
服务发现·软件工程·需求分析·软件需求·敏捷流程
音元系统2 天前
项目开发中途遇到困难的解决方案
后端·目标跟踪·中间件·服务发现
秋意零4 天前
【排坑指南】MySQL初始化后,Nacos与微服务无法连接??
运维·数据库·mysql·微服务·nacos·报错
技术管理修行5 天前
【二】主流架构模式深度对比:单体、前后端分离与微服务
微服务·云原生·架构·服务发现·前后端分离·单体架构
Mr_hwt_1235 天前
基于nacos和gateway搭建微服务管理平台详细教程
java·spring boot·spring cloud·微服务·nacos
代码改变生活-1208 天前
Nacos 2.4.3 初始化配置连接数据库、开启鉴权及程序注册
nacos
workflower17 天前
量子比特实现方式
数据仓库·服务发现·需求分析·量子计算·软件需求