什么是注册中心?
注册中心主要有三种角色:
-
服务提供者(RPC Server):在启动时,向 Registry 注册自身服务,并向 Registry 定期发送心跳汇报存活状态。
-
服务消费者(RPC Client):在启动时,向 Registry 订阅服务,把 Registry 返回的服务节点列表缓存在本地内存中,并与 RPC Sever 建立连接。
-
服务注册中心(Registry):用于保存 RPC Server 的注册信息,当 RPC Server 节点发生变更时,Registry 会同步变更,RPC Client 感知后会刷新本地 内存中缓存的服务节点列表。
最后,RPC Client 从本地缓存的服务节点列表中,基于负载均衡算法选择一台 RPC Sever 发起调用。
注册中心需要实现功能
根据注册中心原理的描述,注册中心必须实现以下功能,偷个懒,直接贴幅图:
常用注册中心
1、Zookeeper
这个说起来有点意思的是官方并没有说他是一个注册中心,但是国内Dubbo场景下很多都是使用Zookeeper来完成了注册中心的功能。
当然这有很多历史原因,这里我们就不追溯了。ZooKeeper是非常经典的服务注册中心中间件,在国内环境下,由于受到Dubbo框架的影响,大部分情况下认为Zookeeper是RPC服务框架下注册中心最好选择,随着Dubbo框架的不断开发优化,和各种注册中心组件的诞生,即使是RPC框架,现在的注册中心也逐步放弃了ZooKeeper。在常用的开发集群环境中,ZooKeeper依然起到十分重要的作用,Java体系中,大部分的集群环境都是依赖ZooKeeper管理服务的各个节点。
Zookeeper如何实现注册中心
Zookeeper可以充当一个服务注册表(Service Registry),让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(Ip+端口)去访问具体的服务提供者。如下图所示:
每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /{service}/{version}/{ip:port} 。
比如我们的HelloWorldService部署到两台机器,那么Zookeeper上就会创建两条目录:
-
/HelloWorldService/1.0.0/100.19.20.01:16888
-
/HelloWorldService/1.0.0/100.19.20.02:16888
这么描述有点不好理解,下图更直观:
在zookeeper中,进行服务注册,实际上就是在zookeeper中创建了一个znode节点,该节点存储了该服务的IP、端口、调用方式(协议、序列化方式)等。该节点承担着最重要的职责,它由服务提供者(发布服务时)创建,以供服务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及得知如何调用。
RPC服务注册/发现过程简述如下:
-
服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
-
服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
-
当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
-
当某个服务的所有服务器都下线了,那么这个服务也就下线了。
-
同样,当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
-
服务提供方可以根据服务消费者的数量来作为服务下线的依据。
zookeeper提供了“心跳检测”功能:它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除。
2、Nacos
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。
Nacos 主要特点
服务发现和服务健康监测:
-
Nacos 支持基于 DNS 和基于 RPC 的服务发现。服务提供者使用原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。
-
Nacos 提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
动态配置服务:
-
动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
-
动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
-
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
-
Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
动态 DNS 服务:
-
动态 DNS 服务支持权重路由,让您更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能让您更容易地实现以 DNS 协议为基础的服务发现,以帮助您消除耦合到厂商私有服务发现 API 上的风险。
-
Nacos 提供了一些简单的 DNS APIs TODO 帮助您管理服务的关联域名和可用的 IP:PORT 列表。
小节一下:
-
Nacos是阿里开源的,支持基于 DNS 和基于 RPC 的服务发现。
-
Nacos的注册中心支持CP也支持AP,对他来说只是一个命令的切换,随你玩,还支持各种注册中心迁移到Nacos,反正一句话,只要你想要的他就有。
-
Nacos除了服务的注册发现之外,还支持动态配置服务,一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。
3、Eureka
Eureka 架构图
什么,上面这幅图看起来很复杂?那我给你贴个简化版:
Eureka 特点
-
可用性(AP原则):Eureka 在设计时就紧遵AP原则,Eureka的集群中,只要有一台Eureka还在,就能保证注册服务可用,只不过查到的信息可能不是最新的(不保证强一致性)。
-
去中心化架构:Eureka Server 可以运行多个实例来构建集群,不同于 ZooKeeper 的选举 leader 的过程,Eureka Server 采用的是Peer to Peer 对等通信。这是一种去中心化的架构,无 master/slave 之分,每一个 Peer 都是对等的。节点通过彼此互相注册来提高可用性,每个节点需要添加一个或多个有效的 serviceUrl 指向其他节点。每个节点都可被视为其他节点的副本。
-
请求自动切换:在集群环境中如果某台 Eureka Server 宕机,Eureka Client 的请求会自动切换到新的 Eureka Server 节点上,当宕机的服务器重新恢复后,Eureka 会再次将其纳入到服务器集群管理之中。
-
节点间操作复制:当节点开始接受客户端请求时,所有的操作都会在节点间进行复制操作,将请求复制到该 Eureka Server 当前所知的其它所有节点中。
-
自动注册&心跳:当一个新的 Eureka Server 节点启动后,会首先尝试从邻近节点获取所有注册列表信息,并完成初始化。Eureka Server 通过 getEurekaServiceUrls() 方法获取所有的节点,并且会通过心跳契约的方式定期更新。
-
自动下线:默认情况下,如果 Eureka Server 在一定时间内没有接收到某个服务实例的心跳(默认周期为30秒),Eureka Server 将会注销该实例(默认为90秒, eureka.instance.lease-expiration-duration-in-seconds 进行自定义配置)。
-
保护模式:当 Eureka Server 节点在短时间内丢失过多的心跳时,那么这个节点就会进入自我保护模式。
除了上述特点,Eureka还有一种自我保护机制,如果在15分钟内超过 85% 的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:
-
Eureka不再从注册表中移除因为长时间没有收到心跳而过期的服务;
-
Eureka仍然能够接受新服务注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)
-
当网络稳定时,当前实例新注册的信息会被同步到其它节点中。
Eureka工作流程
了解完 Eureka 核心概念,自我保护机制,以及集群内的工作原理后,我们来整体梳理一下 Eureka 的工作流程:
-
Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息。
-
Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务。
-
Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常。
-
当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例。
-
单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端。
-
当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式。
-
Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地。
-
服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。
-
Eureka Client 获取到目标服务器信息,发起服务调用。
-
Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除。
通过分析 Eureka 工作原理,我可以明显地感觉到 Eureka 的设计之巧妙,完美地解决了注册中心的稳定性和高可用性。
Eureka 为了保障注册中心的高可用性,容忍了数据的非强一致性,服务节点间的数据可能不一致, Client-Server 间的数据可能不一致。比较适合跨越多机房、对注册中心服务可用性要求较高的使用场景。