迈出云原生重要一步 — Dubbo 3 应用级服务发现
Dubbo 与开源中国共同策划【Dubbo 云原生之路】系列文章,和大家一起回顾 Apache Dubbo 社区的发展。这是系列第二篇。系列文章主要涵盖 Dubbo 技术解读、社区运营、应用案例解析三大部分。
在这里,我们也向所有的 Dubbo 用户和开发者发出投稿邀请,如果你正在使用 Dubbo,或是正在为 Dubbo 贡献力量,欢迎和我们分享你的开发使用经验,优质文章也会收录进【Dubbo 云原生之路】系列。
花名陆龟,Github 账号 Chickenlj,Apache Dubbo PMC,项目核心开发,见证了 Dubbo 重启开源,到从 Apache 基金会毕业的整个过程。现任职阿里云云原生应用平台团队,参与服务框架、微服务相关工作,目前主要在推动 Dubbo 3.0 - Dubbo 云原生。
一、服务发现(Service Discovery)概述
在使用微服务构建复杂的分布式系统时,如何感知 backend 服务实例的动态上下线,也是微服务框架最需要关心并解决的问题之一。
下图是微服务中 Service Discovery 的基本工作原理图,微服务体系中的实例大概可分为三种角色:服务提供者(Provider)、服务消费者(Consumer)和注册中心(Registry)。
-
支持几十万/上百万级集群实例的地址发现 -
与不同的微服务体系(如 Spring Cloud)实现在地址发现层面的互通
二、Dubbo 地址发现机制解析
<dubbo:service interface="org.apache.dubbo.samples.basic.api.DemoService" ref="demoService"/>
<dubbo:service interface="org.apache.dubbo.samples.basic.api.GreetingService" ref="greetingService"/>
2.1 “接口粒度” 服务发现
192.168.0.103 实例注册的数据:
dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266
dubbo://192.168.0.103:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816
192.168.0.104 实例注册的数据:
dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.DemoService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.DemoService&methods=testVoid,sayHello&pid=995&release=2.7.7&side=provider×tamp=1596988171266
dubbo://192.168.0.104:20880/org.apache.dubbo.samples.basic.api.GreetingService?anyhost=true&application=demo-provider&default=true&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.samples.basic.api.GreetingService&methods=greeting&pid=995&release=2.7.7&side=provider×tamp=1596988170816
2.2 “应用粒度” 服务发现
192.168.0.103 实例数据:
{
"name": "demo-provider",
"id": "192.168.0.103:20880",
"address": "192.168.0.103",
"port": 20880,
"metadata": {
"dubbo.endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"dubbo.metadata.storage-type": "local",
"dubbo.revision": "6785535733750099598"
},
"time": 1583461240877
}
192.168.0.104 实例数据:
{
"name": "demo-provider",
"id": "192.168.0.104:20880",
"address": "192.168.0.104",
"port": 20880,
"metadata": {
"dubbo.endpoints": "[{"port":20880,"protocol":"dubbo"}]",
"dubbo.metadata.storage-type": "local",
"dubbo.revision": "7829635812370099387"
},
"time": 1583461240947
}
对比以上两种不同粒度的服务发现模式,从 “接口粒度” 升级到 “应用粒度” 后我们可以总结出最大的区别是:注册中心数据量不再与接口数成正比,不论应用提供有多少接口,注册中心只有一条实例数据。
那么接下来我们详细看下这个变化给 Dubbo 带来了哪些好处。
三、Dubbo 应用级服务发现的意义
我们先说结论,应用级服务发现给 Dubbo 带来以下优势:
-
与业界主流微服务模型对齐,比如 SpringCloud、Kubernetes Native Service 等 -
提升性能与可伸缩性。注册中心数据的重新组织(减少),能最大幅度的减轻注册中心的存储、推送压力,进而减少 Dubbo Consumer 侧的地址计算压力;集群规模也开始变得可预测、可评估(与 RPC 接口数量无关,只与实例部署规模相关)
3.1 对齐主流微服务模型
-
实例地址,服务消费方需要知道地址以建立链接 -
RPC 方法定义,服务消费方需要知道 RPC 服务的具体定义,不论服务类型是 rest 或 rmi 等
-
服务注册由平台接管,provider 不再需要关心服务注册 -
consumer 端服务发现将是 Dubbo 关注的重点,通过对接平台层的 API-Server、DNS 等,Dubbo client 可以通过一个 Service Name(通常对应到 Application Name)查询到一组 Endpoints(一组运行 provider 的 pod),通过将 Endpoints 映射到 Dubbo 内部地址列表,以驱动 Dubbo 内置的负载均衡机制工作
-
Service Name - > Application Name,Dubbo 应用和 Kubernetes 服务一一对应,对于微服务运维和建设环节透明,与开发阶段解耦
apiVersion: v1
kind: Service
metadata:
name:provider-app-namespec:
selector:
app:provider-app-name
ports:
-protocol:TCP
port:
targetPort:9376
-
Service Name - > Dubbo RPC Service,Kubernetes 要维护调度的服务与应用内建 RPC 服务绑定,维护的服务数量变多
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-1
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-2
spec:
selector:
app: provider-app-name
ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
name: rpc-service-N
spec:
selector:
app: provider-app-name
ports: ##
...
3.2 更大规模的微服务集群 - 解决性能瓶颈
-
对于 Spring Cloud 和 Kubernetes 模型,注册中心只会存储一条 DEMO - 10.210.134.30+metadata 的数据 -
对于老的 Dubbo 模型,注册中心存储了三条接口粒度的数据,分别对应三个接口 DemoService 1 2 3,并且很多的址数据都是重复的
四、应用级服务发现工作原理
4.1 设计原则
-
新的服务发现模型要实现对原有 Dubbo 消费端开发者的无感知迁移,即 Dubbo 继续面向 RPC 服务编程、面向 RPC 服务治理,做到对用户侧完全无感知 -
建立 Consumer 与 Provider 间的自动化 RPC 服务元数据协调机制,解决传统微服务模型无法同步 RPC 级接口配置的缺点
4.2 基本原理详解
{
"name": "provider-app-name",
"id": "192.168.0.102:20880",
"address": "192.168.0.102",
"port": 20880,
"sslPort": null,
"payload": {
"id": null,
"name": "provider-app-name",
"metadata": {
"metadataService": "{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}",
"endpoints": "[{\"port\":20880,\"protocol\":\"dubbo\"}]",
"storage-type": "local",
"revision": "6785535733750099598",
}
},
"registrationTimeUTC": 1583461240877,
"serviceType": "DYNAMIC",
"uriSpec": null
}
[
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314",
"dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider×tamp=1583469714314"
]
-
一部分和实例相关的数据继续保留在注册中心,如 ip、port、机器标识等 -
另一部分和 RPC 方法相关的数据从注册中心移除,转而通过 MetadataService 暴露给消费端
-
服务提供者启动,首先解析应用定义的“普通服务”并依次注册为 RPC 服务,紧接着注册内建的 MetadataService 服务,最后打开 TCP 监听端口 -
启动完成后,将实例信息注册到注册中心(仅限 ip、port 等实例相关数据),提供者启动完成 -
服务消费者启动,首先依据其要“消费的 provider 应用名”到注册中心查询地址列表,并完成订阅(以实现后续地址变更自动通知) -
消费端拿到地址列表后,紧接着对 MetadataService 发起调用,返回结果中包含了所有应用定义的“普通服务”及其相关配置信息 -
至此,消费者可以接收外部流量,并对提供者发起 Dubbo RPC 调用
4.3 服务自省中的关键机制
-
内建 MetadataService -
独立的元数据中心,通过中细化的元数据集群协调数据
<!-- 框架直接通过 RPC Service 1/2/N 去注册中心查询或订阅地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="RPC Service 1" />
<dubbo:reference interface="RPC Service 2" />
<dubbo:reference interface="RPC Service N" />
<!-- 框架需要通过额外的 provided-by="provider-app-x" 才能在注册中心查询或订阅到地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:reference interface="RPC Service 1" provided-by="provider-app-x"/>
<dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />
<dubbo:reference interface="RPC Service N" provided-by="provider-app-y" />
五、总结与展望
觉得不错,请点个在看呀