注册中心原理和选型:Zookeeper、Eureka、Nacos、Consul和Etcd

166次阅读  |  发布于1年以前

讲解5种常用的注册中心,对比其流程和原理,无论是面试还是技术选型,都非常有帮助。

大家好!对于注册中心,在写这篇文章前,我其实只对ETCD有比较深入的了解,但是对于Zookeeper和其它的注册中心了解甚少,甚至都没有考虑过ETCD和Zookeeper是否适合作为注册中心。

经过近2周的学习,原来注册中心除了ETCD和Zookeeper,常用的还有Eureka、Nacos、Consul,下面我们就对这些常用的注册中心,初探它们的异同,便于后续技术选型。

全文接近 8千字,有点长,建议先收藏,再慢慢看,下面是文章目录:

注册中心基本概念

什么是注册中心?

注册中心主要有三种角色:

最后,RPC Client 从本地缓存的服务节点列表中,基于负载均衡算法选择一台 RPC Sever 发起调用。

注册中心需要实现功能

根据注册中心原理的描述,注册中心必须实现以下功能,偷个懒,直接贴幅图:

注册中心基础扫盲

这块知识如果大家已经知道,可以直接跳过,主要是为了扫盲。

CAP理论

CAP理论是分布式架构中重要理论:

关于 P 的理解,我觉得是在整个系统中某个部分,挂掉了,或者宕机了,并不影响整个系统的运作或者说使用,而可用性是,某个系统的某个节点挂了,但是并不影响系统的接受或者发出请求。

CAP 不可能都取,只能取其中2个的原因如下:

分布式系统协议

一致性协议算法主要有Paxos、Raft、ZAB。

Paxos算法是Leslie Lamport在1990年提出的一种基于消息传递的一致性算法,非常难以理解,基于Paxos协议的数据同步与传统主备方式最大的区别在于:Paxos只需超过半数的副本在线且相互通信正常,就可以保证服务的持续可用,且数据不丢失。

Raft是斯坦福大学的Diego Ongaro、John Ousterhout两个人以易理解为目标设计的一致性算法,已经有了十几种语言的Raft算法实现框架,较为出名的有etcd,Google的Kubernetes也是用了etcd作为他的服务发现框架。

Raft是Paxos的简化版,与Paxos相比,Raft强调的是易理解、易实现,Raft和Paxos一样只要保证超过半数的节点正常就能够提供服务。这篇文章 [《ETCD教程-2.Raft协议》] 详细讲解了Raft原理,非常有意思,感兴趣的同学可以看看。

ZooKeeper Atomic Broadcast (ZAB, ZooKeeper原子消息广播协议)是ZooKeeper实现分布式数据一致性的核心算法,ZAB借鉴Paxos算法,但又不像Paxos算法那样,是一种通用的分布式一致性算法,它是一种特别为ZooKeeper专门设计的支持崩溃恢复的原子广播协议。

常用注册中心

这里主要介绍5种常用的注册中心,分别为Zookeeper、Eureka、Nacos、Consul和ETCD

Zookeeper

这个说起来有点意思的是官方并没有说他是一个注册中心,但是国内Dubbo场景下很多都是使用Zookeeper来完成了注册中心的功能。

当然这有很多历史原因,这里我们就不追溯了。ZooKeeper是非常经典的服务注册中心中间件,在国内环境下,由于受到Dubbo框架的影响,大部分情况下认为Zookeeper是RPC服务框架下注册中心最好选择,随着Dubbo框架的不断开发优化,和各种注册中心组件的诞生,即使是RPC框架,现在的注册中心也逐步放弃了ZooKeeper。在常用的开发集群环境中,ZooKeeper依然起到十分重要的作用,Java体系中,大部分的集群环境都是依赖ZooKeeper管理服务的各个节点。

Zookeeper如何实现注册中心

具体可参考这篇文章 [《Zookeeper用作注册中心的原理》] ,下面的内容都出自该文章。

Zookeeper可以充当一个服务注册表(Service Registry),让多个服务提供者形成一个集群,让服务消费者通过服务注册表获取具体的服务访问地址(Ip+端口)去访问具体的服务提供者。如下图所示:

每当一个服务提供者部署后都要将自己的服务注册到zookeeper的某一路径上: /{service}/{version}/{ip:port} 。

比如我们的HelloWorldService部署到两台机器,那么Zookeeper上就会创建两条目录:

这么描述有点不好理解,下图更直观:

在zookeeper中,进行服务注册,实际上就是在zookeeper中创建了一个znode节点,该节点存储了该服务的IP、端口、调用方式(协议、序列化方式)等。该节点承担着最重要的职责,它由服务提供者(发布服务时)创建,以供服务消费者获取节点中的信息,从而定位到服务提供者真正网络拓扑位置以及得知如何调用。

RPC服务注册/发现过程简述如下:

  1. 服务提供者启动时,会将其服务名称,ip地址注册到配置中心。
  2. 服务消费者在第一次调用服务时,会通过注册中心找到相应的服务的IP地址列表,并缓存到本地,以供后续使用。当消费者调用服务时,不会再去请求注册中心,而是直接通过负载均衡算法从IP列表中取一个服务提供者的服务器调用服务。
  3. 当服务提供者的某台服务器宕机或下线时,相应的ip会从服务提供者IP列表中移除。同时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
  4. 当某个服务的所有服务器都下线了,那么这个服务也就下线了。
  5. 同样,当服务提供者的某台服务器上线时,注册中心会将新的服务IP地址列表发送给服务消费者机器,缓存在消费者本机。
  6. 服务提供方可以根据服务消费者的数量来作为服务下线的依据。

zookeeper提供了“心跳检测”功能:它会定时向各个服务提供者发送一个请求(实际上建立的是一个 socket 长连接),如果长期没有响应,服务中心就认为该服务提供者已经“挂了”,并将其剔除。

比如100.100.0.237这台机器如果宕机了,那么zookeeper上的路径就会只剩/HelloWorldService/1.0.0/100.100.0.238:16888。

Zookeeper的Watch机制其实就是一种推拉结合的模式

Zookeeper不适合作为注册中心

作为一个分布式协同服务,ZooKeeper非常好,但是对于Service发现服务来说就不合适了,因为对于Service发现服务来说就算是返回了包含不实的信息的结果也比什么都不返回要好。所以当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。

但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30 ~ 120s, 且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。

所以说,作为注册中心,可用性的要求要高于一致性!

在 CAP 模型中,Zookeeper整体遵循一致性(CP)原则,即在任何时候对 Zookeeper 的访问请求能得到一致的数据结果,但是当机器下线或者宕机时,不能保证服务可用性。

那为什么Zookeeper不使用最终一致性(AP)模型呢?因为这个依赖Zookeeper的核心算法是ZAB,所有设计都是为了强一致性。这个对于分布式协调系统,完全没没有毛病,但是你如果将Zookeeper为分布式协调服务所做的一致性保障,用在注册中心,或者说服务发现场景,这个其实就不合适。

Eureka

Eureka 架构图

什么,上面这幅图看起来很复杂?那我给你贴个简化版:

Eureka 特点

除了上述特点,Eureka还有一种自我保护机制,如果在15分钟内超过 85% 的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:

Eureka工作流程

了解完 Eureka 核心概念,自我保护机制,以及集群内的工作原理后,我们来整体梳理一下 Eureka 的工作流程:

  1. Eureka Server 启动成功,等待服务端注册。在启动过程中如果配置了集群,集群之间定时通过 Replicate 同步注册表,每个 Eureka Server 都存在独立完整的服务注册表信息。
  2. Eureka Client 启动时根据配置的 Eureka Server 地址去注册中心注册服务。
  3. Eureka Client 会每 30s 向 Eureka Server 发送一次心跳请求,证明客户端服务正常。
  4. 当 Eureka Server 90s 内没有收到 Eureka Client 的心跳,注册中心则认为该节点失效,会注销该实例。
  5. 单位时间内 Eureka Server 统计到有大量的 Eureka Client 没有上送心跳,则认为可能为网络异常,进入自我保护机制,不再剔除没有上送心跳的客户端。
  6. 当 Eureka Client 心跳请求恢复正常之后,Eureka Server 自动退出自我保护模式。
  7. Eureka Client 定时全量或者增量从注册中心获取服务注册表,并且将获取到的信息缓存到本地。
  8. 服务调用时,Eureka Client 会先从本地缓存找寻调取的服务。如果获取不到,先从注册中心刷新注册表,再同步到本地缓存。
  9. Eureka Client 获取到目标服务器信息,发起服务调用。
  10. Eureka Client 程序关闭时向 Eureka Server 发送取消请求,Eureka Server 将实例从注册表中删除。

通过分析 Eureka 工作原理,我可以明显地感觉到 Eureka 的设计之巧妙,完美地解决了注册中心的稳定性和高可用性。

Eureka 为了保障注册中心的高可用性,容忍了数据的非强一致性,服务节点间的数据可能不一致, Client-Server 间的数据可能不一致。比较适合跨越多机房、对注册中心服务可用性要求较高的使用场景。

Nacos

以下内容摘抄自Nacos官网:https://nacos.io/zh-cn/docs/what-is-nacos.html

Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

Nacos 主要特点

服务发现和服务健康监测

动态配置服务

动态 DNS 服务

小节一下:

  • Nacos是阿里开源的,支持基于 DNS 和基于 RPC 的服务发现。
  • Nacos的注册中心支持CP也支持AP,对他来说只是一个命令的切换,随你玩,还支持各种注册中心迁移到Nacos,反正一句话,只要你想要的他就有。
  • Nacos除了服务的注册发现之外,还支持动态配置服务,一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心

Consul

Consul 是 HashiCorp 公司推出的开源工具,用于实现分布式系统的服务发现与配置。与其它分布式服务注册与发现的方案,Consul 的方案更“一站式”,内置了服务注册与发现框 架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具(比如 ZooKeeper 等)。

Consul 使用起来也较为简单,使用 Go 语言编写,因此具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署,与 Docker 等轻量级容器可无缝配合。

Consul 的调用过程

  1. 当 Producer 启动的时候,会向 Consul 发送一个 post 请求,告诉 Consul 自己的 IP 和 Port;
  2. Consul 接收到 Producer 的注册后,每隔 10s(默认)会向 Producer 发送一个健康检查的请求,检验 Producer 是否健康;
  3. 当 Consumer 发送 GET 方式请求 /api/address 到 Producer 时,会先从 Consul 中拿到一个存储服务 IP 和 Port 的临时表,从表中拿到 Producer 的 IP 和 Port 后再发送 GET 方式请求 /api/address;
  4. 该临时表每隔 10s 会更新,只包含有通过了健康检查的 Producer。

Consul 主要特征

多数据中心

这里纯属了解,学习一下 Consul 的多数据中心是如何实现的。

Consul支持开箱即用的多数据中心,这意味着用户不需要担心需要建立额外的抽象层让业务扩展到多个区域。

在上图中有两个DataCenter,他们通过Internet互联,同时请注意为了提高通信效率,只有Server节点才加入跨数据中心的通信。

在单个数据中心中,Consul分为Client和Server两种节点(所有的节点也被称为Agent),Server节点保存数据,Client负责健康检查及转发数据请求到Server;Server节点有一个Leader和多个Follower,Leader节点会将数据同步到Follower,Server的数量推荐是3个或者5个,在Leader挂掉的时候会启动选举机制产生一个新的Leader。

集群内的Consul节点通过gossip协议(流言协议)维护成员关系,也就是说某个节点了解集群内现在还有哪些节点,这些节点是Client还是Server。单个数据中心的流言协议同时使用TCP和UDP通信,并且都使用8301端口。跨数据中心的流言协议也同时使用TCP和UDP通信,端口使用8302。

集群内数据的读写请求既可以直接发到Server,也可以通过Client使用RPC转发到Server,请求最终会到达Leader节点,在允许数据延时的情况下,读请求也可以在普通的Server节点完成,集群内数据的读写和复制都是通过TCP的8300端口完成。

ETCD

etcd是一个Go言编写的分布式、高可用的一致性键值存储系统,用于提供可靠的分布式键值存储、配置共享和服务发现等功能。

ETCD 特点

ETCD 框架

etcd主要分为四个部分:

通常,一个用户的请求发送过来,会经由HTTP Server转发给Store进行具体的事务处理,如果涉及到节点的修改,则交给Raft模块进行状态的变更、日志的记录,然后再同步给别的etcd节点以确认数据提交,最后进行数据的提交,再次同步。

更多关于ETCD相关知识,可以查看该文章 [《肝了一个月的ETCD,从Raft原理到实践》]

注册中心对比&选型

注册中心对比

注册中心选型

关于注册中心的对比和选型,其实上面已经讲的非常清楚了,我给出一些个人理解:

尽信书则不如无书,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激。

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8