注册中心的产生是基于用来解耦服务提供者(Provider)与消费者(Consumer)的关系,分布式设计架构下,众多的服务提供者的数量并不是动态不变的,在传统的静态LB的方案中,无法很好感知这种变化;
在分布式架构中,除了要考虑服务提供者与消费者的关系,还要考虑如何一系列更复杂的问题:
- 服务提供者注册后,如何被及时发现;
- 服务宕机后,如何及时下线;
- 服务调用异常时,如何进行有效规避雪崩问题的出现;
- 在大流量、大压力的情况下,如何进行有效的水平扩展;
- 注册中心如何实现自身的高可用;
目前,业界根据不同的需求和企业,主流的注册中心有eureka、consul、nacos、zookeeper。
eureka是
序号 | 比较项 | Eureka | zookeeper | Nacos | Consul |
1 | 集群结构 | 平级 | 主从 | 支持平级和主从 | 主从 |
2 | 集群角色 | 主人 | Leader、followerobserver | leader、follower、candidate | server-leader、server以及client |
3 | 是否可以及时知道服务状态变化 | 不能及时知道 | 会及时知道 | 不能及时知道 | 不能及时知道 |
4 | 一致性协议(CAP) | 注重可用性(AP) | 注重一致性(CP) | 支持CP和AP-如何实现 | 注重一致性(CP) |
5 | 雪崩保护 | 有 | 没有 | 有 | 没有 |
6 | 社区是否活跃 | Eureka2.0不再维护了 | 持续维护 | 持续维护 | 持续维护 |
7 | 管理端 | 有现成的eureka管理端 | 没有现成的管理端 | 有现成的管理端 | 有现成的管理端 |
8 | 负载均衡策略 | 使用ribbon实现 | 一般可以直接采用RPC的负载均衡 | 权重/metadata/Selector | Fabio |
9 | 权限控制 | 无 | 使用ACL实现节点权限控制 | RBAC-用户、角色、权限 | ACL |
10 | SpringCloud集成 | 支持 | 支持 | 支持 | 支持 |
11 | 健康检查 | ClientBeat | KeepAlive | TCP/HTTP/MYSQL/ClientBeat | TCP/HTTP/gRPC/Cmd |
12 | 自动注销实例 | 支持 | 支持 | 支持 | 不支持 |
13 | 访问协议 | HTTP | TCP | HTTP/DNS | HTTP/DNS |
14 | 是否可用作配置中心 | 否 | 是 | 是 | 是 |
15 | 多数据中心 | 不支持 | 不支持 | 不支持 | 支持 |
16 | 跨注册中心同步 | 不支持 | 不支持 | 支持 | 支持 |
17 | Dubbo集成 | 不支持 | 支持 | 支持 | 不支持 |
18 | K8S集成 | 支持 | 支持 | 支持 | 支持 |
注册中心选型
Eureka2已经不维护了,不建议继续使用,nacos既可以做配置中心,还可以做注册中心,属于比较好的选择。Consul目前的主要发展方向放在了Service Mesh。至于zookeeper作为服务发现有一个巨大的缺陷:
作为一个分布式协同服务,ZooKeeper非常好,但是对于Service发现服务来说就不合适了,因为对于Service发现服务来说就算是返回了包含不实的信息的结果也比什么都不返回要好。所以当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。
但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。
所以说,作为注册中心,可用性的要求要高于一致性!
在 CAP 模型中,Zookeeper整体遵循一致性(CP)原则,即在任何时候对 Zookeeper 的访问请求能得到一致的数据结果,但是当机器下线或者宕机时,不能保证服务可用性。
另外一个重要影响选型的就是健康检查的速度和方式
健康检查
Zookeeper和Eureka都实现了一种TTL的机制,就是如果客户端在一定时间内没有向注册中心发送心跳,则会将这个客户端摘除。Eureka做的更好的一点在于它允许在注册服务的时候,自定义检查自身状态的健康检查方法。这在服务实例能够保持心跳上报的场景下,是一种比较好的体验,在Dubbo和SpringCloud这两大体系内,也被培养成用户心智上的默认行为。Nacos也支持这种TTL机制,不过这与ConfigServer在阿里巴巴内部的机制又有一些区别。Nacos目前支持临时实例使用心跳上报方式维持活性,发送心跳的周期默认是5秒,Nacos服务端会在15秒没收到心跳后将实例设置为不健康,在30秒没收到心跳时将这个临时实例摘除。
有一些服务无法上报心跳,但是可以提供一个检测接口,由外部去探测。这样的服务也是广泛存在的,而且以我们的经验,这些服务对服务发现和负载均衡的需求同样强烈。服务端健康检查最常见的方式是TCP端口探测和HTTP接口返回码探测,这两种探测方式因为其协议的通用性可以支持绝大多数的健康检查场景。在其他一些特殊的场景中,可能还需要执行特殊的接口才能判断服务是否可用。例如部署了数据库的主备,数据库的主备可能会在某些情况下切换,需要通过服务名对外提供访问,保证当前访问的库是主库。此时的健康检查接口,可能就是一个检查数据库是否是主库的MYSQL命令了。
客户端健康检查和服务端健康检查有一些不同的关注点。客户端健康检查主要关注客户端上报心跳的方式、服务端摘除不健康客户端的机制。而服务端健康检查,则关注探测客户端的方式、灵敏度及设置客户端健康状态的机制。从实现复杂性来说,服务端探测肯定是要更加复杂的,因为需要服务端根据注册服务配置的健康检查方式,去执行相应的接口,判断相应的返回结果,并做好重试机制和线程池的管理。这与客户端探测,只需要等待心跳,然后刷新TTL是不一样的。同时服务端健康检查无法摘除不健康实例,这意味着只要注册过的服务实例,如果不调用接口主动注销,这些服务实例都需要去维持健康检查的探测任务,而客户端则可以随时摘除不健康实例,减轻服务端的压力。
Nacos既支持客户端的健康检查,也支持服务端的健康检查,同一个服务可以切换健康检查模式。我们认为这种健康检查方式的多样性非常重要,这样可以支持各种类型的服务,让这些服务都可以使用到Nacos的负载均衡能力。Nacos下一步要做的是实现健康检查方式的用户扩展机制,不管是服务端探测还是客户端探测。这样可以支持用户传入一条业务语义的请求,然后由Nacos去执行,做到健康检查的定制。
容量
据说,Nacos在内部淘汰Zookeeper和Eureka的过程中,容量是一个非常重要的因素。
Zookeeper的容量,从存储节点数来说,可以达到百万级别。不过如上面所说,这并不代表容量的全部,当大量的实例上下线时,Zookeeper的表现并不稳定,同时在推送机制上的缺陷,会引起客户端的资源占用上升,从而性能急剧下降。
Eureka在服务实例规模在5000左右的时候,就已经出现服务不可用的问题,甚至在压测的过程中,如果并发的线程数过高,就会造成Eureka crash。不过如果服务规模在1000上下,几乎目前所有的注册中心都可以满足。毕竟我们看到Eureka作为SpringCloud的注册中心,在国内也没有看到很广泛的对于容量或者性能的问题报告。
Nacos在开源版本中,服务实例注册的支撑量约为100万,服务的数量可以达到10万以上。在实际的部署环境中,这个数字还会因为机器、网络的配置与JVM参数的不同,可能会有所差别。图9展示了Nacos在使用1.0.0版本进行压力测试后的结果总结,针对容量、并发、扩展性和延时等进行了测试和统计。
完整的测试报告可以参考Nacos官网:
Nacos service discovery performance test report
参考文献:
主流微服务注册中心浅析和对比 – 知乎
微服务注册中心技术选型:5种主流注册中心,哪个最香?_程序员阿宇的博客-CSDN博客