二、 应用级服务发现机制详解
1. 设计目标
• 显著降低服务发现过程的资源消耗,包括提升注册中心容量上限、降低消费端地址解析资源占用等,使得Dubbo3框架能够支持更大规模集群的服务治理,实现无限水平扩容。
• 适配底层基础设施服务发现模型,如Kubernetes、Service Mesh等。
2. 背景
我们从Dubbo最经典的工作原理图说起,Dubbo从设计之初就内置了服务地址发现的能力,Provider注册地址到注册中心,Consumer通过订阅实时获取注册中心的地址更新,在收到地址列表后,consumer基于特定的负载均衡策略发起对provider的RPC调用。
在这个过程中:
• 每个Provider通过特定的key向注册中心注册本机可访问地址。
• 注册中心通过这个key对provider实例地址进行聚合。
• Consumer通过同样的key从注册中心订阅,以便及时收到聚合后的地址列表。
这里,我们对接口级地址发现的内部数据结构进行详细分析。
首先,看右下角provider实例内部的数据与行为。Provider部署的应用中通常会有多个Service,也就是Dubbo2中的服务,每个service都可能会有其独有的配置,我们所讲的service服务发布的过程,其实就是基于这个服务配置生成地址URL的过程,生成的地址数据如图所示;同样的,其他服务也都会生成地址。
然后,看一下注册中心的地址数据存储结构,注册中心以service服务名为数据划分依据,将一个服务下的所有地址数据都作为子节点进行聚合,子节点的内容就是实际可访问的IP地址,也就是我们Dubbo中URL,格式就是刚才provider实例生成的。
这里把URL地址数据划分成了几份:
• 首先是实例可访问地址,主要信息包含ip port,是消费端将基于这条数据生成tcp网络链接,作为后续RPC数据的传输载体。
• 其次是RPC元数据,元数据用于定义和描述一次RPC请求,一方面表明这条地址数据是与某条具体的RPC服务有关的,它的版本号、分组以及方法相关信息,另一方面表明。
• 下一部分是RPC配置数据,部分配置用于控制RPC调用的行为,还有一部分配置用于同步Provider进程实例的状态,典型的如超时时间、数据编码的序列化方式等。
• 最后一部分是自定义的元数据,这部分内容区别于以上框架预定义的各项配置,给了用户更大的灵活性,用户可任意扩展并添加自定义元数据,以进一步丰富实例状态。
结合以上两页对于Dubbo2接口级地址模型的分析,以及最开始的Dubbo基本原理图,我们可以得出这么几条结论:
• 地址发现聚合的key就是RPC粒度的服务。
• 注册中心同步的数据不止包含地址,还包含了各种元数据以及配置。
• 得益于1与2,Dubbo实现了支持应用、RPC服务、方法粒度的服务治理能力。
这就是一直以来Dubbo2在易用性、服务治理功能性、可扩展性上强于很多服务框架的真正原因。
一个事物总是有其两面性,Dubbo2地址模型带来易用性和强大功能的同时,也给整个架构的水平可扩展性带来了一些限制。这个问题在普通规模的微服务集群下是完全感知不到的,而随着集群规模的增长,当整个集群内应用、机器达到一定数量时,整个集群内的各个组件才开始遇到规模瓶颈。在总结包括阿里巴巴、工商银行等多个典型的用户在生产环境特点后,我们总结出以下两点突出问题(如图中红色所示):
• 首先,注册中心集群容量达到上限阈值。由于所有的URL地址数据都被发送到注册中心,注册中心的存储容量达到上限,推送效率也随之下降。
• 而在消费端这一侧,Dubbo2框架常驻内存已超40%,每次地址推送带来的CPU等资源消耗率也非常高,影响正常的业务调用。
为什么会出现这个问题?我们以一个具体provider示例进行展开,来尝试说明为何应用在接口级地址模型下容易遇到容量问题。
青蓝色部分,假设这里有一个普通的Dubbo Provider应用,该应用内部定义有10个RPC Service,应用被部署在100个机器实例上。这个应用在集群中产生的数据量将会是“Service数*机器实例数”,也就是10*100=1000条。数据被从两个维度放大:
• 从地址角度。100条唯一的实例地址,被放大10倍。
• 从服务角度。10条唯一的服务元数据,被放大100倍。
《Apache Dubbo微服务开发从入门到精通》——服务发现与负载均衡——二、 应用级服务发现机制详解(下):https://developer.aliyun.com/article/1224471