Skip to content

Commit 0327486

Browse files
committed
init some columns: proposals and summerofcode
1 parent 0aeb2cb commit 0327486

23 files changed

+940
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.iml
2+
.idea/

images/mesh-mix.png

325 KB
Loading

images/mesh-thinsdk-1.png

45.4 KB
Loading

images/mesh-xds-1.png

25.7 KB
Loading

images/mesh-xds-2.png

39.3 KB
Loading

images/multi-instance.png

189 KB
Loading

images/observability-2.png

24.2 KB
Loading

images/observability.png

24.2 KB
Loading

proposals/D0-triple.md

Whitespace-only changes.

proposals/D1-application-level-service-discovery.md

Whitespace-only changes.

proposals/D1.1-service-discovery-reflection.md

Whitespace-only changes.

proposals/D2-multi-instances.md

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# D2 - Multi-instances
2+
* Authors: Albumen, Dewei Gong, Jun Liu
3+
4+
## Objective
5+
在本设计内,我们主要涉及的内容为Dubbo的指标体系,并且需要设计的内容总共涉及三块,指标收集、本地聚合、指标推送。
6+
* 指标收集:我们将Dubbo内部需要监控的指标推送至统一的Collector中进行存储。
7+
* 本地聚合:指标收集获取的均为基础指标,而一些分位数指标则需通过本地聚合计算得出。
8+
* 指标推送:收集和聚合后的指标通过一定的方式推送至第三方服务器,本文档只涉及Prometheus。
9+
10+
* 我们将原来的MetricsConfig配置重构后供可观测性使用,并且只有在柔性服务开启或者Metrics,Config配置存在的情况下才会开启指标收集的功能。
11+
12+
## Background
13+
Java 提供的静态变量(static field)能力可以将持有对象引用的行为绑定到类上面来,这给开发者提供了巨大的便利。注入单例模式、工厂模式等设计模式的实现方案都依赖了静态变量的功能。通过使用静态变量,开发者可以在任何时间、任何地点简单地获取到所需要的对象信息。
14+
15+
```java
16+
public class Test {
17+
public static Object obj;
18+
}
19+
Test.obj = xxx;
20+
```
21+
22+
在一直以来的 Dubbo 框架开发中,静态变量受到了广泛地应用,诸如使用一个全局共享的 ConfigManager 来存储全局配置信息、ServiceRepository 来存储服务信息,不论从中心化管理配置或者是参数获取的便利性的角度来说,这种设计都是最佳的。在 Dubbo 2.7 以前的所有版本,Dubbo 所需要的运行时配置信息都通过全局静态变量获取,通过 RPC 服务三元组(interface + version + group)的方式进行唯一定位。
23+
24+
但是随着 Dubbo 用户基数的不断扩大以及在阿里集团内由 Dubbo 作为内核的 HSF3 框架都对原来的这种设计模式提出了挑战。
25+
26+
对于开源用户,社区收到的诉求主要包括以下几点:
27+
1. 在同一个应用内能够创建多个三元组一样的订阅。这个行为在 Dubbo 2.7 中虽然没有做强限制,但是由于 Dubbo 很多参数是取自全局的,而这个获取的索引使用的就是三元组。如果用户创建了两个三元组一样的订阅,他们的参数会被相互覆盖,地址推送等功能也会收到很大的影响。
28+
2. Java 提供了自定义 ClassLoader 的机制可以自定义指定类的加载器来源,但是对于 Dubbo 来说并没有去支持多 ClassLoader 的场景,在动态代理生成和序列化场景下都不支持 ClassLoader 切换的行为。
29+
3. Dubbo 众多的测试用例都共享了同一份配置信息,导致在进行单元测试的时候极为容易造成环境污染的问题。
30+
31+
对于阿里集团内大规模落地来说,我们遇到的问题主要有:
32+
1. 阿里集团内有众多的中间件框架,这些框架提供了各种各样的类加载方式,同时业务方期望在同一应用内的配置等信息是相互隔离的。
33+
2. 一些业务方的定制逻辑需要支持动态热部署的模式,具体体现在动态对某个虚拟环境进行销毁,这需要 Dubbo 内的生命周期管理更加完善。
34+
3. 集团内有多个对 Spring 容器进行定制化开发的框架,需要 Dubbo 能够支持多个 Spring Context 独立管理生命周期的场景。
35+
36+
基于众多的这些原因,在八月初的时候我们决定对 Dubbo 的生命周期进行重构,经过一个月的紧张开发,目前社区版本已经完整支持了多实例化的功能,Dubbo 的生命周期也变得更加清晰。
37+
38+
## Related Proposals
39+
40+
## Proposal
41+
整个 Dubbo 多实例的设计我们按照了三层模型来配置,分别是 Framework 框架层、Application 应用层、Module 模块层。
42+
43+
[multi-instance](../images/multi-instance.png)
44+
45+
基于三层机制,我们可以将 Dubbo 按照一定规则进行隔离:
46+
1. Framework 与 Framework 之间完全隔离,相当于是使用了两个完全不同的 Dubbo 实例
47+
2. Application 与 Application 之间按照应用名进行隔离,但是相互有些地共享 Protocol、Serialization 层,目标是达到在同一个 dubbo 端口(20880)上可以承载多个应用,而每个应用独立上报地址信息。
48+
3. Module 与 Module 之间可以由用户自定义进行进行隔离,可以是热部署周期的一个状态、也可以是 Spring Context 的一个 Context。通过 Module,用户可以对 Dubbo 的生命周期粒度进行最小的管理。
49+
50+
为了实现 Dubbo 多实例化,Dubbo 框架内做的最多的变化是修改掉大部分的从静态变量中获取的参数的逻辑,最明显的逻辑是 Dubbo 内部用于参数传递的 URL 对象带上了 ScopeModel 状态,这个 ScopeModel 对应的就是上面提到的三层模型的具体数据承载对象。
51+
52+
### 使用方式
53+
54+
多实例重构版本之后的 Dubbo 对于大多数用户的使用来说是无感知的,改造后的 DubboBootstrap 已经变成一个独立的启动器,用户可以通过 DubboBootstrap 定制多实例的使用。
55+
56+
下面是使用多实例的一个简单的例子。
57+
58+
```java
59+
ServiceConfig<DemoService> service = new ServiceConfig<>();
60+
service.setInterface(DemoService.class);
61+
service.setRef(new DemoServiceImpl());
62+
63+
ReferenceConfig<DemoService> reference1 = new ReferenceConfig<>();
64+
reference1.setInterface(DemoService.class);
65+
66+
ReferenceConfig<DemoService> reference2 = new ReferenceConfig<>();
67+
reference2.setInterface(DemoService.class);
68+
69+
// 创建一个启动器(自动创建新 ApplicationModel)
70+
DubboBootstrap bootstrap1 = DubboBootstrap.newInstance();
71+
// 指定应用名
72+
bootstrap1.application(new ApplicationConfig("dubbo-demo-app-1"))
73+
.registry(new RegistryConfig("nacos://localhost:8848"))
74+
// 创建一个模块
75+
.newModule()
76+
// 在模块内发布服务
77+
.service(service)
78+
.endModule()
79+
// 创建一个模块
80+
.newModule()
81+
// 在模块内订阅服务
82+
.reference(reference1)
83+
.endModule()
84+
.start();
85+
86+
// 创建一个启动器(自动创建新 ApplicationModel)
87+
DubboBootstrap bootstrap2 = DubboBootstrap.newInstance();
88+
// 指定应用名
89+
bootstrap2.application(new ApplicationConfig("dubbo-demo-app-2"))
90+
.registry(new RegistryConfig("nacos://localhost:8848"))
91+
// 创建一个模块
92+
.newModule()
93+
// 在模块内订阅服务
94+
.reference(reference2)
95+
.endModule()
96+
.start();
97+
98+
// stub1 与 stub2 是两个独立的订阅,互相隔离
99+
100+
// 订阅的 stub
101+
DemoService stub1 = reference1.get();
102+
System.out.println(stub1.sayHello("Hello World!"));
103+
104+
// 订阅的 stub
105+
DemoService stub2 = reference2.get();
106+
System.out.println(stub2.sayHello("Hello World!"));
107+
108+
bootstrap1.stop();
109+
bootstrap2.stop();
110+
```
111+
112+
这个例子对外发布了一个 DemoService 的服务,由 dubbo-demo-app-1 这个应用提供。同时我们创建了两个订阅,分别是在 dubbo-demo-app-1 应用和 dubbo-demo-app-2 应用中,然后我们去对两个订阅进行调用,得到预期的结果。
113+
114+
这里需要注意的是虽然两个订阅的服务信息是完全一致的,在多实例化改造后,这两个订阅对于消费端来说是完全隔离的,也就是在最新版本的 Dubbo 中是支持三元组一样的情况下通过变更参数来创建多个订阅的行为的了。

proposals/D3-mesh.md

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# Dubbo Mesh (draft)
2+
* Authors: Zhongming Hua, Jun Liu
3+
4+
## Objective
5+
## Background
6+
## Related Proposals
7+
## Proposal
8+
### 场景
9+
1. 场景一(适用不具备Dubbo SDK定制能力,并且完全没有接入Mesh的用户群体):Sidecar仅托管服务发现能力以及进出口流量,该群体有三种分支场景:
10+
○ 希望增加Sidecar组件,来完成Mesh改造。Sidecar仍然发现原有的注册中心(非kubernetes)内的服务,需要定制控制面来适配第三方注册中心。
11+
○ 希望增加Sidecar组件,来完成Mesh改造。服务注册想要切换到控制面官方支持的注册中心,比如istio支持Kubernetes等,此时可以选择采用Dubbo内的 Kubernetes Registry方案。Sidecar发现Kubernetes内的服务。
12+
○ 不希望增加Sidecar,来完成Mesh改造。
13+
2. 场景二(适用已经具备对 Dubbo SDK、数据面、控制面的定制能力,并且完全没有接入Mesh的用户群体):已经基于目前Dubbo版本,做了不同于社区方案的kubernetes 服务注册,比如服务注册模型在kubernetes中的存储模型和存储方式将不一定按照dubbo内的方案来执行。
14+
○ 希望增加Sidecar组件,对接istio、Envoy等,来完成Mesh改造。
15+
○ 希望不增加Sidecar组件,来完成Mesh改造。
16+
17+
### Mesh模式
18+
● 完全Proxy Mesh模式
19+
● 主次模式:Proxy Mesh回切到Proxyless Mesh模式(两种并存,主Proxy Mesh,次Proxyless Mesh)
20+
● 完全Proxyless Mesh模式
21+
#### Proxy Mesh(ThinSDK)模式
22+
描述:Proxy Mesh有两种一种是Sidecar、另一种是集中式Proxy。(是否要考虑集中式Proxy的情况)注:下文提到的Proxy Mesh暂时都指代Sidecar模式。
23+
24+
方案:Proxy Mesh采用Dubbo内部的直连模式来完成Dubbo SDK与Sidecar之间的通信。
25+
26+
待做事项:
27+
1. 缩小Dubbo SDK包(新增一个Dubbo ThinSDK Library,名字叫dubbo-thin.jar ??):dubbo-thin.jar应该更加专注于RPC本身。
28+
○ 服务发现
29+
○ 路由(Router、Loadbalance)
30+
○ 服务注册(Optional)
31+
○ 减少部分可观测性(Optional)
32+
■ Metrics数据上报,如果去掉Dubbo的Metrics上报,能会丢失应用于Sidecar之间的rt损耗等。
33+
■ Tracing:可以去掉。
34+
■ Logging:不能去掉。
35+
2. 减少不必要的类加载
36+
3. 梳理需要适配的内容:
37+
○ Cluster内比如merge功能
38+
4. 增强与Sidecar之间的交互(dubbo 、triple)
39+
○ 健康状态感知(心跳保活)
40+
○ 部分配置露出并且透传,比如timeout、retry等。(主要为请求链路上的配置)
41+
○ 广播模式配置透传
42+
5. 是否要加强Dubbo SDK侧对mesh的配置露出(待讨论):新增MeshConfig,将Dubbo内部的一些模型进行封装,比如sidecar之间的连接数(consumer的connections),改为与sidecar之间的连接数等,让mesh配置更加突出。
43+
44+
#### 主次模式
45+
无需缩小包
46+
方案一:采用新增容错策略、并新增恢复能力(恢复到Proxy Mesh模式)
47+
方案二:通过心跳保活探测来触发切换能力,并通过重连来触发恢复Proxy Mesh模式的能力。
48+
#### Proxyless Mesh模式
+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# 3.1 Dubbo Thin SDK (draft)
2+
* Authors: Zhongming Hua, Jun Liu
3+
4+
## Objective
5+
## Background
6+
## Related Proposals
7+
## Proposal
8+
9+
### 四大流程的核心逻辑介绍
10+
11+
除了应用启动和服务注册流程以外,其他两大流程都是在直连模式下:服务发现以及服务调用流程。其中应用下线不单独列出来主要是优雅下线时候的处理
12+
#### 应用启动
13+
以下是应用启动的大致流程(省略了spring容器启动等与mesh无关的流程):
14+
1. ApplicationDeployer #initialize():注册ShutdownHook ->开启配置中心 -> 加载应用配置 -> 初始化ModuleDeployer -> 开启元数据中心
15+
2. ApplicationDeployer #doStart():ModuleDeployer #start()
16+
3. ModuleDeployer #start():ModuleDeployer #initialize() -> 暴露服务 -> 引用服务
17+
4. ApplicationDeployer #onModuleStarted():暴露 MetadataService 服务-> 上报元数据信息-> 注册应用实例地址
18+
#### 服务暴露
19+
以下是服务暴露的流程:
20+
1. 暴露 injvm 协议的服务
21+
2. 暴露 Triple 协议的服务
22+
3. 发起服务注册:registry 协议
23+
4. 暴露 MetadataService 服务
24+
5. 发起服务注册:service-discovery-registry 协议
25+
#### 服务发现
26+
在应用启动中的服务引用过程包含了服务发现,以下是直连模式下的引用服务流程:
27+
28+
1. TripleProtocol #refer
29+
2. 创建 TripleInvoker 实例
30+
3. 与对端建连(ConnectionManager #connect)
31+
4. 将 TripleInvoker 实例包装成ClusterInvoker,附加集群相关处理能力(Cluster #join)
32+
5. 新增Cluster Interceptor(主要是附加一些容错策略、结果处理策略)
33+
6. 推送consumer端元数据信息
34+
7. 创建代理
35+
36+
#### 服务调用
37+
1. InvokerInvocationHandler #invoke()
38+
2. filter chain处理:ConsumerContextFilter 、FutureFilter 、MonitorFilter 、RouterSnapshotFilter
39+
3. 执行 router chain(直连模式不需要路由)
40+
4. 执行负载均衡策略(由于是直连一个sidecar,所以负载均衡策略没有效果):(AbstractClusterInvoker #select)
41+
5. TripleInvoker #doInvoke()
42+
6. DefaultFuture2 #received
43+
44+
### 四大流程涉及的改造点
45+
#### 应用启动
46+
47+
● Dubbo应用进程与Sidecar生命周期对齐
48+
○ 正常启动后,让Sidecar感知到该Endpoint是健康的。
49+
■ 初步方案:Dubbo应用与Sidecar建连,并且发送POST /healthcheck/ok
50+
○ 运行态:通过健康检查来保活
51+
○ Dubbo应用优雅下线时,需要能够让Sidecar感知到该Endpoint下线了。(应用所在的Container原地热升级、应用优雅下线等场景)
52+
■ 初步方案:发送POST /healthcheck/fail
53+
● 在启动过程中,除了生命周期对齐以外,其他主要需要做缩减的动作,对mesh主流程影响不大。
54+
55+
#### 健康检查
56+
运行态,通过envoy的健康检查来保证Dubbo应用是否正常。目前Triple协议基于gRPC的Health接口实现健康检查。需要支持Envoy的HTTP健康检查Filter:
57+
https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/health_check/v3/health_check.proto#envoy-v3-api-msg-extensions-filters-http-health-check-v3-healthcheck
58+
https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/health_check.proto
59+
#### 服务注册
60+
istio中所支持的注册中心中成熟度最高的是Kubernetes,第一阶段推荐使用Kubernetes Registry。目前已经有Kubernetes Registry的实现,主要以 CRD 的方式存储到 Kubernetes 的 etcd 中:
61+
● 元数据内容存储在annotation中。
62+
● 应用名对应 Kubernetes service模型。
63+
● hosts:{IDL service name}.{namespace}.svc.cluster.local
64+
但是对于Kubernetes 服务注册还缺少了许多内容,应用级别的服务注册需要考虑interface name与应用名称的映射关系,除此之外还有自定义label、namespace等。需要增加对外的配置。
65+
#### 服务发现
66+
服务发现需要解决的问题是如何触发数据面的服务发现。目前Pilot的操作是在集群第一次启动时从Kubernetes中发现全量的Service、Workload数据,并将这些服务发现数据通过xDS下发给Envoy(Pilot-Agent)实例,后续则以增量的方式推送。
67+
在服务发现阶段,Dubbo应用仅仅与Envoy进行建连,并没有发起任何订阅的行为。
68+
#### 服务调用
69+
● 负载均衡策略的对接:交由Sidecar来做:
70+
○ envoy支持的负载均衡策略:https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/load_balancers
71+
● 服务路由:路由规则的存储,将Kubernetes API Server作为Config Store,注册Kubernetes CRD资源来作为路由规则的存储。通过RDS下发路由规则到Sidecar,由Sidecar来做服务路由。
72+
○ 涉及到现有的路由规则如何迁移到istio中路由规则管控的问题。
73+
目前triple协议默认的header:
74+
75+
[:scheme: http, :method: POST, :path: /org.apache.dubbo.demo.GreeterService/sayHello, :authority: 127.0.0.1:50051, grpc-accept-encoding: gzip, te: trailers, content-type: application/grpc+proto, tri-consumer-appname: dubbo-demo-triple-api-consumer]
76+
77+
● 在进行服务调用时:
78+
:authority会被识别成一个virtual host,需要适配
79+
○ 需要支持envoy header:https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_conn_man/headers#config-http-conn-man-headers-custom-request-headers
80+
○ 需要支持envoy router的header:调用时支持Envoy router header:https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/router_filter#id7
81+
○ 对比google grpc 和envoy grpc的差异,适配header内容:https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/core/v3/grpc_service.proto.html#envoy-api-field-core-grpcservice-envoy-grpc
82+
83+
84+
85+
### 会议目的:
86+
● 确定第一阶段的目标
87+
● 讨论整体的方案
88+
89+
### 会议记录:
90+
优雅下线的时候已经有相关的逻辑。
91+
接口级别的服务注册对接sidecar
92+
多实例:应用。
93+
没有mesh 迁移到mesh的方案
94+
gRPC 相关的支持内容调研

0 commit comments

Comments
 (0)