微服务在大型项目开发过程中已经非常普遍,而在通过 RPC 调用微服务时,首要问题是如何获取服务实例的地址。最简单的方式是静态配置,也就是将服务地址写入配置文件中。然而,现代微服务体系中,大部分服务都是动态上线的,在部署之前往往并不知道其确切地址;同时,服务实例的地址也可能因为扩缩容、故障转移等原因而频繁变化。若依赖静态配置,不仅维护成本高,还容易导致调用失败。
为了解决这一问题,我们需要一个专门的组件:服务注册中心。它的职责是动态管理和维护服务提供者的地址信息,并将这些信息提供给服务调用者,从而实现自动化、可扩展的服务寻址机制。
即服务调用者能够自动获取服务提供者地址列表的能力,是微服务架构的灵魂。如上图所示(示意图来自:分布式系统之服务发现(Service Discovery)),一个完整的服务发现架构主要包含三个部分:服务注册中心、服务调用者、服务提供者。其中,服务注册中心是核心组件,本质上可以看作是一个“服务名服务->实例地址”的映射集合(有点类似 DNS 的功能)。
当一个新的服务实例启动时,它需要将自己的元信息(例如服务名、IP 地址、端口、健康状态等)注册到服务注册中心。注册的方式有两种:
当服务调用者需要访问某个服务时,就涉及到“如何获取服务地址”的问题,这就是服务发现的模式。如图所示,主要分为两类(示意图来自:服务发现-从原理到实现):
在理想情况下,服务注册中心只需要一个节点就能完成所有的注册与发现工作。但在实际生产环境中,单节点的注册中心存在明显缺陷
为了提升可靠性和可用性,服务注册中心往往采用多节点集群部署。但一旦进入集群化场景,新的挑战随之而来:如何保证多节点之间的数据一致?如何在网络分区时保证系统的可用性?要理解服务注册中心如何保证可用性和一致性,就需要引入分布式系统的一些基本理论。
这里讨论的一致性概念,不同于 CPU 缓存一致性(Cache Coherence),也不同于传统数据库 ACID 中的一致性(Consistency)。 在分布式系统中,一致性主要指多个节点在面对读写操作时对数据状态达成的共识。也就是说,无论客户端访问哪一个节点,都应该得到符合一致性模型的结果。
常见的一致性模型包括:
一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)三者不可同时满足。对于一个分布式系统来说,网络分区(Partition)是不可避免的,因此在出现分区时,系统必须在一致性(C)和可用性(A)之间做取舍。
需要注意的是,CAP 并不是“随意选择两个”,而是因为 P 是前提条件,一旦发生分区,系统要么保证 CP(牺牲可用性来保证一致性),要么保证 AP(牺牲一致性来保证可用性)。在网络正常、没有分区的情况下,C 和 A 是可以同时满足的。
与强调强一致性的 ACID 不同,BASE 是分布式系统领域的一种实践性理论,其核心思想是:在大规模分布式环境下,为了保证高可用和可扩展性,可以容忍一定程度的“暂时不一致”。BASE 包含三个关键点:
BASE 理论的提出本质上是对 CAP 定理的一种工程解法:既然在分布式系统中强一致性和高可用无法兼得,那就优先保证高可用(A),同时通过软状态和最终一致性机制,在容忍一定“不一致”的前提下,换取系统整体的可扩展性和容错性。
在分布式系统中,单节点的故障是常态而不是例外。为了保证多个节点在面对网络分区、节点宕机、消息丢失等情况时仍能对外提供一致的服务,就需要依赖共识算法来达成多个节点之间的一致性。常见的共识算法有 Paxos、Raft 以及更轻量的 Gossip 协议。
一些常见的误解:使用了 Raft 或者 paxos 的系统都是线性一致性的(即强一致),其实不然,共识算法只能提供基础,要实现线性一致还需要在算法之上做出更多的努力。
Paxos 是由 Leslie Lamport 提出的经典分布式共识算法。它通过提议者(Proposer)、接受者(Acceptor)和学习者(Learner)三类角色,实现分布式节点之间对某个值的达成一致。Paxos 的理论完整性很高,但实现和理解相对复杂,因此在工业界大规模应用中较少直接使用,而更多是作为后续算法的理论基础。
Raft 可以看作是对 Paxos 的工程化改进。它把复杂的一致性问题拆解为几个更容易理解的子问题:领导者选举、日志复制和安全性保证。在一个 Raft 集群中,始终会选出一个 Leader 节点,由 Leader 负责接收客户端请求并同步给 Follower 节点,保证日志顺序和状态机的一致性。由于设计简洁、逻辑清晰,Raft 已成为许多分布式系统(如 Etcd、Consul)的核心算法。这里是两篇帮助理解的可视化:Raft: Understandable Distributed Consensus 和 The Raft Consensus Algorithm
Gossip 协议是一种允许在分布式系统中共享状态的去中心化通信协议,通过这种通信协议,我们可以将信息传播给网络或集群中的所有成员。它的思想源自现实生活中的“谣言传播”:每个节点定期随机选择其他节点,将自己已知的信息传递出去。随着时间推移,所有节点的信息会逐渐收敛到一致状态。Gossip 协议实现简单、扩展性强,特别适合节点规模庞大、对一致性要求不高的场景,例如健康检查、服务心跳同步和分布式缓存。
算法 | 特点 | 优点 | 缺点 / 适用场景 |
---|---|---|---|
Paxos | 最经典的分布式一致性算法,基于提议者、接受者、学习者三角色达成共识 | 理论完整性高,保证强一致性,适合关键业务场景 | 实现复杂,理解困难,工程实践中较少直接使用 |
Raft | 对 Paxos 的工程化改进,核心思路:领导者选举 + 日志复制 + 安全性保证 | 易于理解和实现,逻辑清晰,广泛应用于 etcd、Consul 等系统 | 仍需要领导者节点,Leader 崩溃会有短暂不可用,适合中小规模集群 |
Gossip | 去中心化协议,节点通过“谣言传播”逐步同步状态 | 理解简单,易于实现。节点平等,扩散速度比单主节点快 | 短时间内节点状态可能不一致(最终一致性),节点可能重复收到相同信息 |
以下除 Nacos 内容,均转自分布式系统之服务发现(Service Discovery)。示意图来自 Service Discovery With CRDTs
DNS(Domain Name System)是一种通过解析域名获取 IP 和端口的机制。将 SRV 记录注册到 DNS 服务器上,通过 DNS 解析流程进行解析。但是 DNS 存在两个问题:一是当服务实例启动之后将 SRV 记录注册到 DNS 服务器上比较难,需要手动维护;二是 DNS 严重依赖缓存,服务使用方无法及时知道一个服务实例是否已经停止。
mDNS(multicast DNS 即组播 DNS)是一种零配置的服务发现机制,在内部网络中经常使用,每个服务都有一个内置的 mDNS 响应程序,从而不需要单独的服务注册中心。mDNS 最大的问题就是要求网络基础设施支持 IP 多播(IP multicast),对于云环境来说显然是无法满足的,而且 mDNS 也无法解决 DNS 缓存问题。
DNS 与 mDNS 都具备良好的容错能力,但缺乏服务健康检查和变化通知机制。
Zookeeper 提供分布式协调服务,在分布式系统中常被用于配置管理、名字服务、分布式锁及组管理,通常运行在一组节点上实现容错(当运行在 n 个节点上时能容忍 n/2 个节点同时故障)。
如何通过 Zookeeper 来实现服务发现?Zookeeper 使用临时节点(ephemeral node)来实现服务注册和基本的健康检查功能。每当服务实例启动就会在 Zookeeper 中注册一个临时节点,而当服务实例故障或下线该临时节点会被 Zookeeper 自动删除,如果有其他服务依赖这个服务可以设置监听该服务实例对应的临时节点,当临时节点被删除时,依赖该服务的其他服务会获得通知。依赖 Zookeeper 自身的高可用及临时节点提供的健康检查和监听机制来实现具备容错能力的服务发现机制。
实际开发过程中建议使用 Apache Curator 来替代 Zookeeper 原生客户端库,Apache Curator 通过封装 Zookeeper 原生 API,提供更高抽象层次 API 让 Zookeeper 使用起来更加容易和可靠,而且提供专用于实现服务发现的 API。
Etcd 是一个基于 Raft 共识算法具备线性强一致性(linearizable)的 Key-Value 存储系统,可以为每个 Key 设置 TTL(time to live),当 TTL 过后相应 Key 会自动过期失效。基于 Etcd 构建服务发现解决方案将 Etcd作为服务注册中心,服务实例注册就是在 Etcd 中构建一个 Key-Value 记录,由服务实例自身或代理负责设置并定期更新其关联 Key 的 TTL,如果服务实例故障其对应 Key 就会在 TTL 之后过期失效,相当于将该故障服务实例注销,通过定时心跳以达到监控健康状态的效果。而且 Etcd 提供监听机制,允许为 Key 设置监听器当该 Key 发生变化时,监听器能及时获取通知。Etcd 自身的高可用特性,基于 TTL 提供基本的服务健康检查,基于监听机制及时感知服务实例变化,使 Etcd 成为微服务架构中常用服务发现解决方案。
Consul 是一个成熟的服务发现解决方案。其核心是一个基于 Raft 共识算法具备线性强一致性的 Key-Value 存储系统作为服务注册中心,并提供代理(Agent)机制一方面用于协调服务注册,一方面提供服务健康检查。代理(Agent)会在每个运行服务的节点上启动,获取节点地址并将该服务实例注册到服务注册中心。架构上 Consul 包括两类组件:Server、Agent,服务注册信息保存在 Server 上,通过 Raft 共识算法保证多个 Server 间数据线性强一致,保证服务注册中心高可用;将所有 Agent 作为集群节点,使用 Gossip 协议进行组关系管理和故障探测,当有 Agent 加入(启动)或离开(故障)集群时其他 Agent 会得到通知,实现服务健康检查和监视功能。
Gossip 协议常用于集群组关系管理和故障检测,每个节点都通过一个或多个引导节点加入集群,引导节点有集群中所有节点列表,每个节点都从自己所知节点列表中随机选择一组节点周期性地发送多播消息,最终集群中所有节点都能知道其他节点。这个过程看起来很神奇,实际上 Gossip 协议能在几秒内将消息传遍有上百节点的集群。Akka、Riak、Cassandra 都使用 Gossip 协议维护集群成员列表和故障探测。
此外 Consul 和 Etcd 都非常适合容器环境,因为 Docker 容器启动、停止都会发送事件(Event),基于事件通知机制非常便于将服务实例从 Consul 或 Etcd 上注册、注销。
Nacos是阿里巴巴开源的一款易用平台,专为动态服务发现、配置管理和服务治理设计,旨在帮助开发者快速构建云原生应用和微服务平台。
服务发现与健康检查
动态配置管理
动态 DNS 服务
服务及元数据管理
集群与高可用
安全与权限控制
本文作者:Zerol Acqua
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!