服务注册中心架构演进
1. 概述
服务注册中心(下称注册中心)是微服务架构非常重要的一个组件,在微服务架构里主要起到了协调者的一个作用。因为各个公司的架构、规模、部署环境等等都不尽相同,所以在注册中心在业界有很多不同的实践,包括各种各样的技术选型、层出不穷的技术改进。
本文将从注册中心的功能实现、功能扩展、规模变大等实际情况出发,结合现有的技术框架以及一些国内外公司的技术实践,来介绍下 笔者了解的 注册中心的演进。另外其它例如 DNS、组播等地址发现机制本文不展开讨论,只讨论注册中心。
阅读本文之前,我们先统一一下基本术语,对齐一下大家的理解。
名词 | 解释 |
---|---|
注册中心(Registry) | 服务注册中心,本文主要解释的微服务组件。 |
注册中心客户端(Registry Client) | 不管是服务提供者还是服务调用者,都算是注册中心的客户端,本文里简称客户端。 |
注册中心管理端(Registry Console) | 注册中心数据的管理端,本文里简称管理端 。 |
服务(Service) | 一般是指一个接口,可以包括多个方法。例如订单服务包含有查询订单、新增订单等方法 |
服务提供者(Provider) | 暴露一个监听端口,提供一到多个服务。 |
服务调用者(Consumer) | 连接服务提供者的端口,发起远程调用。 |
2. 注册中心功能
注册中心与配置中心
很多人经常把注册中心和配置中心混为一谈,一般这么认为的因为服务注册的数据其实就是配置的一种,其实这样解释也不无道理,的确注册中心的数据是配置的一种。但是注册中心之所以独立的存在,那是因为注册中心的数据有一定的业务独立性,一般都是为了描述微服务相关的。所以本文的观点就是注册中心完全不依赖配置中心,而是一个独立的系统。
2.1 注册中心需求
注册中心一般包含如下几个功能:
- 服务发现:
- 服务注册/反注册:保存服务提供者和服务调用者的信息
- 服务订阅/取消订阅:服务调用者订阅服务提供者的信息,最好有实时推送的功能
- 服务路由(可选):具有筛选整合服务提供者的能力。
- 服务配置(不包括其它无关配置):
- 配置订阅:服务提供者和服务调用者订阅微服务相关的配置
- 配置下发(可选):主动将配置推送给服务提供者和服务调用者
- 服务健康检测
- 检测服务提供者的健康情况
2.2 一致性分歧
这里不得不提一下,我们知道分布式里一个重要的理论,那就是 CAP。在注册中心的发展上面,一直有两个分支:一个就是 CP 系统,追求数据的强一致性。还有一个是 AP 系统,追求高可用与最终一致。
2.3 为什么不用DNS
DNS 只是到 IP 级别,无法处理端口等信息。DNS 携带的数据较少,例如节点权重、序列化方式等等,无法传递。另外 DNS 没有节点状态管理功能,如果由外部系统刷新,那么将无法剔除死的节点。
3 注册中心发展阶段
注册中心的规模一定是随着业务的发展而发展的,在不同的阶段有不同的技术实现方案。注册中心数据源一般会选择文件存储,数据库存储,KV存储等等。
3.1 小型注册中心
这个阶段的注册中心,一般最关心的肯定是服务发现这个特性,而且可能是一个很小的体量、很短的开发迭代周期、我们需要一个快速开发上手的环境。具体情况:
- 单数据中心
- 服务规模较小:接口数在 5K 以下,注册中心客户端数量在 50K 以下。
3.2 中型注册中心
这个阶段的注册中心,架构已经非常复杂,涉及到跨机房容灾等特性。一般会有专门的技术团队来做注册中心的日常运维。具体情况:
- 多数据中心
- 服务规模较大:接口数在 20K 以下,注册中心客户端数量在200K以下。
3.3 大型注册中心
这个阶段的注册中心,数据量已经非常大,可能一个注册中心已经无法满足需求,必须拆为多个注册中心,甚至需要容量的无限扩展。具体情况:
- 非常多的数据中心
- 服务规模十分大,单节点无法满足全量存储。
4. CP类注册中心演进
典型的有Zookeeper,Consul,etcd等。
阶段一:注册中心高可用
部署5个主节点(只是按经验值举例,3台或者7台都行),只要半数以上存活,其中一个会成为Leader。
客户端随机选择一台直接接入主节点。客户端拿注册中心的地址可以通过DNS或者其它地方动态发现。
管理端从主节点的其中一台读取数据。
阶段二:注册中心提高性能
此时如果读取节点的数据量特别大的话,那么可能会影响性能,那么我们可以做一些读写分离的操作。
在5台主节点之外,部署多台Zookeeper Observer节点(可扩展),客户端接入Observer节点。
主节点不处理长连接请求。
管理端从某个Observer读取数据。
Consul也有Consul Client节点,类似Zookeeper的Observer节点
这样的架构作为小型注册中心基本没啥问题。
** 阶段三:服务高可用**
通过Zookeeper的临时节点可以实现状态检测,但是一般不是很推荐。因为注册中心和服务提供者断开连接的时候,注册中心其实是无法判断服务提供者是服务异常还是只是网络分区,最好是有额外的辅助进行判断。
例如提供一组状态检测服务,部署在机房的不同域(例如跨机架、跨交换机等,越分散越好),进行一定的投票,如果半数以上认为死了,则上报状态给注册中心。
** 阶段四:跨机房容灾**
如果此时出现多个机房,还要做数据共享的话,那么一定需要三个及以上机房。下面的图我就不画多个节点了,Zookeeper以集群的图展示。
每个机房部署相同的节点,当其中一个机房出现网络分区,那么剩下的两个机房继续可用。
状态检测服务只检查自己同机房的节点。
** 阶段5:跨机房数据访问 **
假如每个机房之间的数据是独立的,那么得部署独立的注册中心。
此时如果需要客户端做与多个注册中心连接,或者注册中心之间自己做数据同步。
图 5 展示的是,注册中心直接的节点是独立的不共享的,由客户端进行跨注册中心数据访问,在客户端做数据聚合。
图 6 展示的是,注册中心直接的节点是独立的,但是数据是共享的,由注册中心直接做数据同步合并,客户端无需处理。
Consul 提供了个功能叫跨数据中心访问,但是其实数据是分开存放的。例如 dc1 和 dc2,在网络正常的情况下,dc1 可以访问 dc2 的数据;但是网络断开的时候,dc1 是无法访问 dc2 的数据,dc1 本地并没有存放 dc2 的数据。可以通过第三方实现做数据同步,参考:consul-replicate
这样的架构作为中型注册中心基本没啥问题。
5. AP类注册中心演进
我们会选用一些数据源,例如DB、文件、KV存储等,但是直接接入数据源的就不多见了,一般会有个自己实现的注册中心。在下面的图中,DB、文件、KV存储我们统称“Datasouce(数据源)”。
** 阶段一:注册中心高可用 **
图 7 我们采用数据库主备或者是 Redis 集群作为一个统一的数据源,然后开发 Registry Proxy 程序(以下简称注册中心实例),这些注册中心实例之间并无数据交互,数据统一存在后端的数据源里,实现数据最终一致。
还有一种方案的变种是放在一个文件系统里,自己做数据同步,如图 8 所示。
Eureka 的设计就是图 8 的简化版本,它把 Data replicate 和 Registry Proxy 都放在 Eureka-Server 里。
** 阶段二:注册中心提高性能 **
只有数据源扛得住,注册中心实例其实是可以无限扩展的。
这种代理模式的注册中心还有个好处就是:代理的业务逻辑可以自己编写。这个地方可以优化的地方非常的多。
例如服务节点推送,在CP系统里基本上都是推送全量的服务节点,而在代理里面可以做推送变化部分的服务节点。假如一个服务有1000个服务提供者,5000个服务调用者;当增加了1个服务提供者的时候,原来的推送数量是1001x5000,而代理模式可以进行特殊处理变成1x5000,大大减少推送数据。
** 阶段三:服务高可用 **
同 CP 注册中心高可用。
** 阶段四:跨机房容灾 **
大部分依赖数据源的跨机房容灾。当然可以做一些缓存,例如本地缓存等等。
以数据库为例。
注册中心的只读缓存,如果内存里放得下则可以放在注册中心实例的内存里,如果放不下则可以是单独的存储服务。
当主库机房挂了,其它机房切到新的主库。 切换期间只能从注册中心只读缓存里读数据,但是不能修改数据。
如果是基于文件系统的,那么只有保证网络分区的时候,保证可以脏读即可。
** 阶段5:跨机房数据访问 **
和 CP 类注册中心类似,可能在多个机房都会部署独立的注册中心,而且服务数据是全局共享的。
一种方案就是多个注册中心直接做数据同步、聚合,图9 中的 DB 主从可以换成其它数据源。
另外一种是注册中心实例对数据源的数据多写,图10 中的 DB 主从可以换成其它数据源。这样做的话,每个数据源里的数据是最终一致的。
** 阶段6:数据无限水平扩展 **
当数据量大到单机无法承受,那么就需要进行数据分片了。
有了注册中心实例(Proxy)的存在,这个事情就很好处理了,只需要在这个注册中心实例上增加分片的逻辑,原则上数据是可以无限扩展的,而且也不用修改客户端的逻辑,实现真正的轻客户端。
6. 结束语
最后还是那句话,架构是演进来的,目前绝大部分使用者还属于小型注册中心阶段,真正需要考虑跨机房容灾的其实不多,不需要在一开始就考虑最终级的架构方案。经常听见有的初级使用者就说 Zookeeper 这不好那不行有很多坑,很多时候都是场景没用好或者考虑不够,如果目前就百来个接口千来个客户端的服务注册中心,就没啥好纠结的了,随便哪个方案都能Hold住你的需求。
本文如有理解错误之处,还请指出,十分感谢。