引言
微服务架构在现代软件开发中越来越受欢迎,它通过将系统拆分为多个小型、自治的服务来提高可维护性、可扩展性和灵活性。然而随着服务数量的增多,服务之间的通信何发现变得更加复杂。本报告旨在深入探讨微服务中的注册与发现,介绍其背景、核心概念、实现技术以及应用实例。
背景与概念
在微服架构中,服务通常是独立部署的,它们可能会在分布式环境中的不同主机上运行。服务之间需要相互通信,但由于服务的数量和位置的变化,需要一种机制来自动识别和定位服务。这就是服务注册与发现的作用。
服务注册
服务注册是将服务的元数据(如服务的名称、地址、端口等)注册到一个中心化的注册中心或服务注册表中。注册中心充当服务的目录,存储所有可用的服务信息
服务发现
服务发现是指客户端应用程序通过查询注册中心来查询需要调用的服务的位置,客户端不需要硬编码服务的位置,而是通过机制来获取。
实现技术
常用的服务注册中心组件有Consul、Eureka、etcd、Zookeeper、Nacos。接下来会对这些组件进行详细的分析。
数据模型
注册中心的核心数据是服务名称和它对应的网络地址。当服务注册了多个实例时,我们需要对不健康的实例进行过滤或者针对实例的一些特征进行流量的分配,那么需要在实例上存储一些例如健康状态、权重等属性。随着服务规模的扩大,又需要在整个服务级别设定一些权限规则,以及对所有实例都生效的一些开关,于是在服务级别又会设立一些属性。再往后,发现单个服务的实例又会划分为多个子集的需求,例如一个服务是多机房部署的,那么可能需要对每个机房做不同的配置这样又需要在服务和实例之间再设定一个数据级别。
另外需要考虑的是数据的隔离模型,作为一个共享服务的组件,需要能够在多个用户或者业务方使用的情况下,保证数据的隔离和安全。
注册中心 | 数据模型 | 隔离模型 |
---|---|---|
Nacos | 服务-集群-实例三层模型 | 四层逻辑隔离模型 |
Zookeeper | k-v | --- |
Eureka/Consul | 实例模型 | --- |
服务的分级模型:
服务的逻辑隔离模型:
数据一致性
数据一致性可以归为两类,一种是基于Leader的非对称部署的单点写一致性,一种是对称部署的多写一致性。
注册中心 | 一致性协议 | 特点 |
---|---|---|
Nacos | 简化的Raft(CP),Distro(AP) | 具备机房容灾,集群扩展能力 |
Zookeeper | ZAB | 保证数据的强一致性,缺乏机房容灾,无法适应大型场景 |
Eureka | Renew |
负载均衡
负载均衡严格的说并不算传统注册中心的功能。一般来说服务发现的完成流程应该是先从注册中心获得服务的实例列表,然后根据自身的需求来选择其中的部分实例或者按照一定的流量分配机制来访问不同的服务提供者,因此注册中心本身一般不限定服务消费者的访问策略。Eureka、Zookeeper包括Consul本身都没有去实现可配置及可扩展的负载均衡机制,Eureka的负载均衡是由Ribbon来完成的,而Consul则是由Fabio做负载均衡。
服务消费者往往不关心所访问的服务提供者的负载均衡,它们只关心以最高效和正确的访问服务提供者的服务。而服务提供者,则非常关心自身被访问的流量的调配。因此服务提供者需要能够完全掌握服务的流量调配,并可以动态调整。目前的负载均衡由基于权重、服务提供者负载、响应时间、标签等策略。
- Ribbon(客户端负载均衡),主要是选择合适现有的IRule,ServerListFilter等接口,或自己继承这些接口,实现自己的过滤逻辑
- RoundRobinRule,轮询,Ribbon的默认负载均衡策略
- RandomRule,随机
- RetryRule,先按照轮询的策略获取服务,如果获取服务失败则在指定时间内进行重试,获得可用的服务
- WeightResponseTimeRule,对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择
- BestAvailableRule,先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
- AvailablityFilteringRure,先过滤掉故障实例,在选择并发量较小的实例
- ZoneAvoidanceRule,默认规则,复合判断server所在区域的性能和servier的可用性选择服务器
- Nacos(服务端负载均衡),除了提供基于健康检查和权重的负载均衡方式外,还提供了基于第三方CMDB的标签负载均衡器
注册中心 | 负载均衡 | |
---|---|---|
Nacos | nacos | |
Zookeeper | --- | |
Eureka | ribbon |
健康检查
Zookeeper和Eureka都是实现一种TTL机制,就是如果客户端在一定时间内没有向注册中心发送心跳,则会将这个客户端摘除。Eureka允许在注册服务的时候自定义检查自身状态的健康检查方法。在Dubbo和SpringCloud这两大体系内,也是使用TTL作为默认健康检查机制。Nacos目前支持临时实例使用心跳上报方式维持活性,发送心跳的周期默认是5s,Nacos服务端会在15s没有收到心跳将实例设置为不健康,在30s没有收到心跳时将这个临时实例摘除。
客户端健康检查和服务端健康检查有一些不同的关注点。客户端健康检查只要关心客户端上报心跳的方式,服务端摘除不健康客户端的机制。而服务端健康检查,则关注探测客户端的方式、灵敏度及设置客户端健康状态的机制。Nacos既支持客户端健康检查,也支持服务端健康检查
性能与容量
影响读写性能的因素有很多,一致性协议、机器的配置、集群的规模、存量数据的规模、数据结构以及读写逻辑的设计等。但是并不是性能越高越好,因为追求性能往往需要在其他方面做出牺牲。Zookeeper在写性能上可以达到上万的TPS,但是写逻辑是通过k-v进行的,内部没有聚合,其次Zookeeper舍弃了服务发现的基本功能,如健康检查、友好的查询接口等,最后Paxos协议本身就限制了Zookeeper的集群规模。
注册中心 | 容量 | |
---|---|---|
Nacos | 10W+ | |
Zookeeper | 百万级 | |
Eureka | 5000左右 |
易用性
Zookeeper的易用性比较差,客户端使用比较复杂,没有针对服务发现的模型设计以及响应的API封装,对多语言的支持也不太好,同时也没有比较好用的控制台进行运维管理。
Eureka和Nacos有针对服务注册与发现的客户端,基于springCloud体系的starter,帮助用户以非常低的成本无感知的做到服务注册与发现。同时还暴露标准的HTTP接口,支持多语言和跨平台访问。
集群扩展性
Zookeeper使用的ZAB协议,由于是单点写,在集群扩展上不具备优势。Eurake在协议上说理论可以扩展到很大的规模,因为都是点对点的数据同步,但是性能有很大的问题。
集群扩展性的另一方面是多地域部署和容灾支持。当讲究集群的高可用和稳定性以及网络上的跨地域延迟要求能够在每个地域都部署集群的时候,我们现有的方案有多机房容灾、异地多活、多数据中心等。
多机房容灾问题,基于Leader写的协议是无法支持的,意味着Zookeeper不能在没有人工干预的情况下做到多机房容灾。Eurake的部署模式天然支持多机房容灾,因为Eurake采用的是纯临时实例的注册模式:不持久化、所有数据同通过客户端心跳上报补偿。Nacos支持两种模式的部署,一种是AP协议的部署,可以完美替代当前的Zookeeper、Eurake并支持多机房容灾。另一种是CP模式,不支持多机房容灾。
小结
注册中心 | 数据结构 | 数据一致性 | 负载均衡 | 健康检查 | 容量 | 易用性 | 集群扩展性 |
---|---|---|---|---|---|---|---|
Nacos | 三层(Service-Cluster-instance) | Raft, Distro | nacos | TTL | 10W+ | 推荐 | 支持多机房容灾 |
Eurake | 单层(instance) | Renew | Ribbon | TTL | 5000左右 | 推荐 | 支持多机房容灾 |
Zookeeper | k-v结构 | ZAB | - | TTL | 100W | 不推荐 | 不支持多机房容灾 |
应用案例
- Hadoop生态系统使用Zookeeper管理各个组件的状态和位置,实现高可用、故障转移等功能。
- Nerfix的微服务架构中使用Euraka作为服务注册与发现以及故障转移和负载均衡等功能
- Nacos作为微服务架构中主流的服务注册与发现中心被广泛使用。
总结和展望
服务注册与发现是微服务架构中的关键组成部分,它为分布式系统提供了自动化的服务管理和通信机制。不同的实现技术适用于不同的场景,开发者可以根据需求选择合适的工具。随着微服务架构的发展,服务注册与发现的技术也在不断演进,未来将更加强调性能、安全性和多云支持等方面的创新。
参考文献
Netflix Eureka Documentation: https://github.com/Netflix/eureka
Apache ZooKeeper Documentation: https://zookeeper.apache.org/doc/r3.7.0/
Nacos架构&原理https://developer.aliyun.com/ebook/36?spm=a2c6h.20345107.ebook-index.18.152c2984fsi5ST