主流中间件选型手册(1)--注册中心
为什么
理解注册中心的必要性,就需要了解软件架构的发展历程。
系统架构的发展历程

为什么需要注册中心
上面的微服务架构采用直连的方式,每一个机器都需要维护更新自己需要连接的机器的IP,将来地址出现变更,还需要及时更新。在集群内部的节点越来越多的时候,开发者管理起来将会非常混乱。此时加入注册中心,就无需将消费者和服务提供者绑定了,提供者宕机不会对消费者产生直接的影响,所有的机器只需要和注册中心去交互。服务方与注册中心之间通过“心跳”机制进行监控。实现服务的自动注册、发现、状态监控:

是什么
注册中心一般会存放机器IP和URL之间的映射,并且在其客户端一般都会附带负载均衡的功能帮助用户开箱即用调用其他机器的服务。还会通过心跳机制实现服务的自动注册、发现、状态监控。
怎么用
开源中间件
zookeeper
简单介绍
最初是Hadoop的子项目,用来管理分布式中的集群。一般用作配置中心、注册中心、分布式锁
简单使用
安装以及命令行的使用:https://juejin.cn/post/7025887917243383844
- 常见的客户端:Zookeeper Java客户端、Apache Curator 开源客户端
Curator 是netflix开源的,Java 语言的。Curator 把常用 ZooKeeper 服务开发功能做了封装。在会话重新连接、Watch 反复注册、多种异常处理等使用场景中有很多自动处理。
- curator-framework 包是对 ZK 底层 API 的一 些封装。
- curator-recipes 包封装了一些 ZK 服务的高级特性,如: Cache 事件监听、选举、分布式锁。
nacos
简单介绍
阿里开源,动态服务发现和服务健康监测、动态服务配置、服务元数据及流量管理。
简单使用
下载安装包:https://github.com/alibaba/Nacos/releases。解压,进入nacos目录。
单机部署:修改配置文件中的启动模式export MODE="cluster"为:export MODE="standalone",不修改会有问题,之后执行:bin/startup.sh ‐m standalone。访问nocas的管理端:http://localhost:8848/nacos ,默认的用户名密码是 nocas/nocas。
集群部署文档: https://nacos.io/zhcn/docs/clustermodequickstart.html,提供了三种方式,推荐使用DNS+内网SLB+三节点Nacos。配置的时候最好使用外置数据库,conf\application.properties中配置外置的数据源,并且执行对应的SQL:conf\nacosmysql.sql。conf\cluster.conf.example改为cluster.conf,添加节点配置。bin\startup.sh中修改对应的堆内存大小防止超出物理内存。登录控制台可以看到集群管理中的节点列表是一Leader和二FOLLOWER。之后在NGINX中配置相关的反向代理即可:
upstream nacoscluster {
server 127.0.0.1:8850;
server 127.0.0.1:8849;
server 127.0.0.1:8848;
}
server {
listen 8847;
server_name localhost;
location /nacos/ {
proxy_pass http://nacoscluster/nacos/;
}
相关使用文档如下,不再赘述,用前一定要看:
- 和springboot结合时候的参考使用(不推荐):https://nacos.io/zh-cn/docs/quick-start-spring-boot.html
- 和springCloud结合时候的参考使用:https://nacos.io/zh-cn/docs/quick-start-spring-cloud.html
- 使用配置中心的使用参考:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config
- 相关的版本选择:https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E
- 相关的配置表:https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-discovery
eureka
简单介绍
Eureka架构中的三个核心角色:
- 服务注册中心:Eureka的服务端应用,提供服务注册和发现功能
- 服务提供者:可以是SpringBoot应用,也可以是其它任意技术实现,只要对外提供的是Rest风格服务即可。
- 服务消费者:消费应用从注册中心获取服务列表,得知每个服务方的信息,知道去哪里调用服务方。
简单使用
这里不再赘述。不怎么用了
开源中间件原理剖析
nacos 原理
nacos 来源
Nacos/nɑ:kəʊs/是Dynamic Namingand Configuration Service
阿里内部的 **Configserver** 非持久注册中心,**VIPServer**** 持久化注册中心,**Diamond** 配置中心。开源的时候考虑到用户体量可能没那么大又合并为一个产品,就是Nacos,对应阿里公有云的就是MSE微服务引擎。**
- 开源是为了像k8s一样加速云计算发展,清楚开源的价值是促进云的发展,保证开源的可持续发展。以开源为内核,以商业化为扩展;开源做生态(生态、开放),商业化做企业级特性(易用、安全),阿里内部做性能和高可用(性能、高可用);开源做组件,商业化做解决方案;并且随着时间推移,基本按照这思路完成的正循环。
- 开源是为了成为默认标准,避免商业化产品不断兼容其他产品
- 开源是为了在易用、规模、实时、稳定沉淀核心竞争力,围绕阿里 Dubbo和Spring-cloud-alibaba生态进行推广,建立阿里DNS(Dubbo+Nacos+Spring-cloud-alibaba/Seata/Sentinel)微服务最佳实践。
nacos架构
详细参考官方文档:https://nacos.io/zh-cn/docs/architecture.html
**NamingService: 命名服务,注册中心核心接口 **
**ConfigService:配置服务,配置中心核心接口 **
控制台:服务和配置的管理。
OpenAPI文档:https://nacos.io/zhcn/docs/openapi.html
nacos 架构和原理电子书:https://developer.aliyun.com/ebook/36?spm=a2c6h.20345107.ebook-index.18.152c2984fsi5ST
NamingService 原理简单概括

服务注册与服务同步 + 服务心跳与健康检查
Nacos Client会通过发送REST请求的方式向Nacos Server注册自己的服务,提供自 身的元数据,比如ip地址、端口等信息。Nacos Server接收到注册请求后,就会把这些元数据信 息存储在一个双层的内存Map中。
注册表结构
Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();
�
- namespace 一般用来区分环境,dev和prod以及stage,只是推荐,但是namespace也可以用来做多租户,一个租户就是一个namespace,group再用来区分环境也是可以的。
- Group:最好是按照项目为单位划分,一般用于配置中心的配合隔离。
- Service内部是不同的Cluster :是一个Map<name, Cluster>,一般是有用于多地部署。loadbalancer一般会先使用同一个cluster的节点
- 持久实例和临时实例:是一个Set,区别是nacos重启之后会不会保留。IP、端口、权重、健康状态、响应时间都是在这个维度去维护的。

源码图
客户端:包含服务注册与心跳任务的流程
在服务注册后,Nacos Client会维护一个定时心跳来持续通知Nacos Server,说明服 务一直处于可用状态,防止被剔除。默认5s发送一次心跳。

服务端:包含服务注册,集群节点间数据同步,服务心跳健康检测
Nacos Server会开启一个定时任务用来检查注册服务实例的健康情况,对于超过 15s没有收到客户端心跳的实例会将它的healthy属性置为false,客户端服务发现时不会返回,如果某个实例超过30秒没有收到心跳,直接剔除该实例,被剔除的实例如果恢复发送心跳则会重新注册。

原理图

服务发现:
服务消费者(Nacos Client)在调用服务提供者的服务时,会发送一个REST请求给 Nacos Server,获取上面注册的服务清单,并且缓存在Nacos Client本地,同时会在Nacos Client本地开启一个定时任务定时拉取服务端最新的注册表信息更新到本地缓存。
源码图

原理图

服务调用:
一般会和ribbon或者Spring Cloud 自己实现的 LoadBalancer联合起来使用,

上面只是介绍了负载均衡器,还需要发起请求的工具,一般实现http接口调用的除了常见的RPC框架Dubbo之外,还有一些轻量级的,比如:
- HttpClient:Apache Jakarta Common 下的子项目,相比传统 JDK 自带的 URLConnection,使客户端发送 HTTP 请求变得容易,提高了开发的效率。
- HttpURLConnection:Java 的标准类,继承自 URLConnection,使用比较复杂,不像 HttpClient 那样容易使用。
- Okhttp:安卓用的多,处理网络请求。用于替代 HttpUrlConnection 和 Apache HttpClient。
- RestTemplate:Spring提供的用于访问Rest服务的客户端,提供多种便捷访问远程Http服务的方法,RestTemplate默认依赖 jdk的HTTP连接工具。
- WebClient:是从Spring WebFlux 5.0版本开始提供的一个非阻塞的基于响应式编程的进行Http请求的客户端工具。它的响应式编程的基于Reactor的,提供了标准Http请求方式对 应的get、post、put、delete等方法
上述都是非常轻量的,和Dubbo可以站在一个水平线的就是 Feign 了。Feign是Netflix开发的声明式、模板化的HTTP客户端。Spring Cloud openfeign对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。这里先不详细叙述Feign原理,是RPC框架的内容。
原理图

Nacos + ribbon 实现平滑上下线
基于Nacos服务地址动态感知原理实现ribbon远程调用平滑上下线:
https://blog.csdn.net/qq_37362891/article/details/119993038
CAP 分布式一致性实现
P(分区容错):多节点部署的系统,由于网络原因节点之间无法通信同步数据,此时虽然网络分区了但是依旧需要对外提供服务,不能因为分区导致整个系统不能提供服务了。
此时:
- 如果要保证整个分布式系统的数据一致性(C),要牺牲掉可用性(A),整个分布式系统对外暂时不可用,不然client 数据查询的结果就不一致了。
- 如果要保证A那肯定要牺牲掉C,因为数据还没在节点间同步,client查询数据结果肯定不一样
BASE:CAP 是三选二,BASE 是CAP折中,都保证但是有先后顺序,先保证集群是可用的,过段时间再保证数据的一致性。最终一致性。
AP Distro
AP的系统符合BASE原则,三个节点挂了两个,系统还是基本能用的(BA),整个系统的各节点间的数据是不一致的,但是等另外两个节点恢复了,数据会同步过去(E),对于中间暂时的数据不一致状态可以称为软状态(S)。
Distro 具体流程参见上面的注册时候 Server 的处理流程。
CP Raft 原理
脑裂:节点分区时,集群会分裂成小集群,各自选出自己的master节点,导致原集群出现多个 master 节点。
脑裂处理:leader选举要求节点的投票数量> 总节点数量/2,保证了集群出现分区,无论如何最多只有一个小集群能选出leader。
集群节点一般推荐是奇数个:偶数节点的集群一旦对半分区,整个集群无法选出leader,集群不可用。容错能力相同的情况下奇数节点比偶数更节约资源,比如5个节点挂两个还能选leader,6个节点最多也只能挂两个节点才能保证其能选leader。
Raft原理简介:
- 角色:candidate leader follower
- 写数据。所有修改只能通过leader。先写到本地日志文件,下次心跳会同步给follower,ack返回leader。leader 写到内存,并且告诉其他节点commit,提交到内存。(先写日志,再同步内存)最后返回。
- leader 挂了,达到超时时间没有收到心跳,就认为leader挂了,随机休眠之后就会发起投票,150-300ms之间,先变为候选者,先给自己投票,发给其他人,如果其他人是休眠,没有发起投票,就会认可你(而不是ZAB那样必须给自己一票开始比较)。只有同时苏醒才会重新投票。
- leader 选举完之后会同步数据给 follower,使用心跳包实现数据同步,心跳超时时间过了就会给 follower 发心跳。
- 如果没有超过半数就需要重新发选票,注意自己会给自己投票,3个节点,只要加上自己两个投了就可以,如果是4个节点加上自己3个投了自己就可以。
- 举例网络分区:5个节点,分区后,AB一起,CDE一起,A 是leader,A没办法提交,因为没有过半。此时CDE选举C是leader,数据写到C是可以成功的。分区恢复之后,要把C作为leader,因为周期term更大。所以周期更大的leader就是最新的leader。
http://thesecretlivesofdata.com/raft/
Nacos 自己实现的 raft 的简单原理

由于自身实现的心跳回调数据有性能问题,并且不是严格的 raft 实现,后面直接使用开源 jraft 来实现。
ZooKeeper 原理
重要概念
- 类文件系统的数据结构:znode 目录节点是一个个子目录项。组合为一个树状结构。
- 持久化节点PERSISTENT:永久存在
- 持久化顺序节点PERSISTENT_SEQUENTIAL:永久存在,自带顺序
- 临时目录节点EPHEMERAL:session 超时会被服务器删除
- 临时顺序节点EPHEMERAL_SEQUENTIAL:临时节点基础上自带顺序
- 容器节点Container:没有子节点时候会被删除。3.5.3 新增
- TTL 节点:过了时间被删除
- znode 节点的一些状态stat字段
- cZxid:创建znode的事务ID(Zxid的值)。
- mZxid:最后修改znode的事务ID。
- pZxid:最后添加或删除子节点的事务ID(子节点列表发生变化才会发生改变)。
- ephemeralOwner:znode是临时znode时,表示znode所有者的 session ID。 如果 znode不是临时znode,则该字段设置为零。
- numChildren:znode的子znode的数量。
- 监听通知机制:客户端可以请求监听任意节点及其子节点,被修改时候都会收到通知。
- 注意:监听器一旦被触发就会删除,所以需要在收到通知后再次创建。
- Zookeeper 事件类型:
- None: 连接建立事件,NodeCreated: 节点创建 ,NodeDeleted: 节点删除,NodeDataChanged:节点数据变化,NodeChildrenChanged:子节点列表变化,DataWatchRemoved:节点监听被移除,ChildWatchRemoved:子节点监听被移除
- 集群模式三种角色:
- Leader:处理读写请求,一个集群一个
- Follower:只处理读请求,参与选举。接收到写请求会转发给Leader
- Observer:只处理读请求,不参与选举
注册中心

服务启动+Leader选举
投票的时候是有选票的概念
源码图

原理图

CAP 分布式一致性实现:ZAB协议
消息广播与崩溃恢复:当 Leader 正常就进入消息广播模式,当 Leader 不可用就进入崩溃恢复模式。zk启动之后就一直在这两个状态里面循环。
过程类似 2PC,ZAB 只需要 Follower 有一半以上返回 Ack 信息就可以执行提交。ZAB协议规定了如果一个事务在一台机器上被处理(commit)成功,那么应该在所有的机器上都被处理成功,哪怕机器出现故障崩溃。
源码图

原理图

附:分布式锁注意点
惊群效应
获取锁失败的所有的连接都在对同一个节点进行监听,当服务器检测到删除事件时,要通知所有的连接,所有的连接同时收到事件,再次并发竞争,这就是羊群效应。
解决惊群效应
获取锁的时候:在对应的锁节点下创建临时顺序节点。判断自己是不是该节点下最小的节点,如果不是,就监听自己前面的一个节点。
释放锁的时候:通知自己后面的第一个顺序的节点。这样就避免了所有节点同时竞争并发锁。
选型总结
| Nacos | zookeeper | eureka | |
|---|---|---|---|
| 分布式一致性算法 | AP:Distro 或 CP:ZAB |
CP:ZAB协议 | AP |
| 实现语言 | Java | Java | Java |
| 多数据中心 | 是 | 否 | 否 |
| 优点 | 有公有云MSE,性能稳定 | 使用者多。可用来当分布式锁 | |
| 缺点 | 和ribbon结合使用无法及时上下线,需要自定义watcher处理。 | zk 关注CP,导致重新选举leader的时候会有暂时不可用的情况。 | 无法支持大集群,社区趋于不维护 |
参考链接
posted on 2025-10-13 01:10 chuchengzhi 阅读(17) 评论(0) 收藏 举报


浙公网安备 33010602011771号