无需改造 dubbo sdk,无需更换 dubbo 协议,直接使用 istio 治理 dubbo 流量。这是史上最简单的改造方法。
step 1. 改造 provider
去掉 registry 配置,让 provider 变成一个纯纯的 dubbo 应用。
修改配置,三个false,address 随便写一个字符串(因为他不能为空):
代码语言:txt复制<beans>
<dubbo:application name="hello-dubbo-provider"/>
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:registry register="false" subscribe="false" check="false" address="none" />
<!--<dubbo:registry address="zookeeper://zk.dubbo:2181" client="curator" />-->
<bean id="demoService" class="tencent.demo.provider.DemoServiceImpl"/>
<dubbo:service interface="tencent.demo.DemoService" ref="demoService" />
</beans>
先在本地启动它。
step 2. 改造 consumer
去掉 registry 配置,让 consumer 变成一个傻傻的 dubbo 应用。
手工指定 service 的服务地址,当然了,要把他变成你部署在 istio 中的 服务名 url="dubbo://hello-dubbo-provider:20880"
。
<beans>
<dubbo:application name="demo-consumer"/>
<dubbo:registry address="none" register="false" subscribe="false" check="false" />
<!--<dubbo:registry address="zookeeper://zk.dubbo:2181" client="curator" />-->
<dubbo:reference id="demoService" check="false" interface="tencent.demo.DemoService" url="dubbo://hello-dubbo-provider:20880" />
</beans>
在 hosts 中映射一下。
代码语言:txt复制127.0.0.1 hello-dubbo-provide
启动 consumer,不出意外,完美运行。
上面的对 dubbo 的改造其实是在使用 dubbo 的调试功能,但他恰恰是 istio 需要的效果。
step 3. 部署到 istio 中
在低版本的 istio (1.3)中,无法解析 dubbo 协议。需要配置 EnvoyFilter。 但配了半天,完全不通 。
以下实验在 istio 1.5.6(腾讯 TKE Mesh 支持) 和 istio 1.6.1 中通过。
经过实验,基于 tcp 服务治理的 dubbo mesh 直接启动成功。
以下是实验过程:示例中的镜像地址目前是公开可测的。
1 创建 ns
代码语言:txt复制apiVersion: v1
kind: Namespace
metadata:
name: dubbo
labels:
istio-injection: enabled
spec:
finalizers:
- kubernetes
2 创建 provider 的部署集
代码语言:txt复制apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-dubbo-provide
namespace: dubbo
labels:
app: hello-dubbo-provide
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: hello-dubbo-provide
version: v1
template:
metadata:
labels:
app: hello-dubbo-provide
version: v1
spec:
containers:
- name: hello-dubbo-provide
image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-provider:1.0.4
command: ["java","-jar","hello-dubbo-provider-fat.jar"]
ports:
- containerPort: 20880
protocol: TCP
---
# 部署 hello-dubbo-provider v2
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-dubbo-provider-v2
namespace: dubbo
labels:
app: hello-dubbo-provide
version: v2
spec:
replicas: 1
selector:
matchLabels:
app: hello-dubbo-provide
version: v2
template:
metadata:
labels:
app: hello-dubbo-provide
version: v2
spec:
containers:
- name: hello-dubbo-provide
image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-provider:2.0.0
command: ["java","-jar","hello-dubbo-provider-fat.jar"]
ports:
- containerPort: 20880
protocol: TCP
3 创建 service
代码语言:txt复制apiVersion: v1
kind: Service
metadata:
name: hello-dubbo-provide
namespace: dubbo
labels:
name: hello-dubbo-provide
spec:
ports:
- name: dubbo-rpc
protocol: TCP
port: 20880
targetPort: 20880
selector:
app: hello-dubbo-provide
4 创建 consumer 部署
代码语言:txt复制apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-dubbo-consume
namespace: dubbo
labels:
app: hello-dubbo-consume
version: v1
spec:
replicas: 10
selector:
matchLabels:
app: hello-dubbo-consume
version: v1
template:
metadata:
labels:
app: hello-dubbo-consume
version: v1
spec:
containers:
- name: hello-dubbo-consume
image: tencent-cloud-one-docker.pkg.coding.net/xyz-demo/images/hello-dubbo-consumer:1.0.3
command: ["java","-jar","hello-dubbo-consumer-fat.jar"]
5 流量/灰度控制
代码语言:txt复制apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: hello-vs
namespace: dubbo
spec:
hosts:
- hello-dubbo-provide
tcp:
- route:
- destination:
host: hello-dubbo-provide
port:
number: 20880
subset: v1
weight: 20
- destination:
host: hello-dubbo-provide
port:
number: 20880
subset: v2
weight: 80
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: hello-subset
namespace: dubbo
spec:
host: hello-dubbo-provide
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
测试结果
部署完成,查看 consumer 的各个 pod 的 log。会发现,少量 consumer 打印了 hello-dubbo-provider:v1 的结果。
代码语言:txt复制2020-06-10T10:58:22.870417943Z Hello 哈哈, V1 @ 2020-06-10 10:58:22 @ 172.24.0.136
2020-06-10T10:58:27.872374594Z Hello 哈哈, V1 @ 2020-06-10 10:58:27 @ 172.24.0.136
2020-06-10T10:58:32.874072253Z Hello 哈哈, V1 @ 2020-06-10 10:58:32 @ 172.24.0.136
v2 的结果的比较多:
代码语言:txt复制2020-06-10T11:00:32.625814149Z 你好世界, 版本 2 升级了这个提示 哈哈, V2 @ 2020-06-10 11:00:32 @ 172.24.0.7
2020-06-10T11:00:37.638914148Z 你好世界, 版本 2 升级了这个提示 哈哈, V2 @ 2020-06-10 11:00:37 @ 172.24.0.7
2020-06-10T11:00:42.635862572Z 你好世界, 版本 2 升级了这个提示 哈哈, V2 @ 2020-06-10 11:00:42 @ 172.24.0.7
调整 vs 的百分比,重启 pod(因为长连接,所以重启),看看他是不是按照指挥来调度。
另外可以使用如下的命令多次执行 consumer 进行验证:
代码语言:txt复制kubectl exec -n dubbo hello-dubbo-consumer-855fcb7878-5qcb4 -- java -jar hello-dubbo-consumer-fat.ja
在 kiali 中,也能看到流量的监控图表。
more: 改造成 http 协议
dubbo 可以通过简单的注册文件的修改,就可以完成通信协议的改变。
依赖包大概需要增加:
代码语言:txt复制 <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.36</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>9.4.29.v20200521</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>9.4.29.v20200521</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.github.briandilley.jsonrpc4j</groupId>
<artifactId>jsonrpc4j</artifactId>
<version>1.2.0</version>
</dependency>
provider 的配置修改
代码语言:txt复制<dubbo:protocol name="http" id="http" port="20880" server="jetty"/>
consumer 的配置修改
代码语言:txt复制 <dubbo:reference id="demoService" check="false" interface="tencent.demo.DemoService" url="http://hello-dubbo-provider:20880" />
修改通信协议之后,程序的行为基本不变,只是每次访问改成了 http,会每次重新连接。
而对于 istio,现在可以通过 接口名称 来进行流量治理了。因为,他的服务的接口名现在放在 url 中了。
下面就是一个访问的示例:
代码语言:txt复制http://hello-dubbo-provider:20880/tencent.demo.DemoService?application=demo-consumer&check=false&init=false&interface=tencent.demo.DemoService&pid=74873®ister.ip=192.168.1.15&remote.application=&side=consumer&sticky=false
在 VirtualService 中,即可 通过 uri 匹配 "tencent.demo.DemoService" 来进行服务治理了。
关于 dubbo http 修改的问题,可以参考这篇文章 《dubbo-http 协议小探和修改尝试》
附:dubbo 的 java 代码
Provider。版本 1 和 2 分别打印了不同的内容。
代码语言:txt复制 public String sayHello(String name) {
String myHost = "";
try {
InetAddress inetAddress = InetAddress.getLocalHost();
myHost = inetAddress.getHostAddress();
} catch (UnknownHostException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String str = format.format(date);
return "你好世界, 版本 2 升级了这个提示 " name ", V2 @ " str " @ " myHost ;
}
consumer 每 5 秒调用一次:
代码语言:txt复制 public static void main(String[] args) throws Exception {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"META-INF/spring/consumer.xml"});
context.start();
DemoService demoService = (DemoService)context.getBean("demoService");
while(true) {
String hello = demoService.sayHello("哈哈");
System.out.println(hello);
Thread.sleep(5 * 1000);
}
}
总结
使用了最简单的方法,将 dubbo 的服务发现和治理功能去掉,保留了他的 rpc 功能,并通过与 istio 一致的部署方法进行服务部署和 TCP 流量操控。
实验证明:不改造 dubbo 框架和业务逻辑的情况下(只改配置文件和依赖包),可以实现 如下目标:
1 基于 TCP 的流量操控,可以控制到 serviceName。
2 基于 HTTP 的流量操控,可以控制到 serviceName 和 interfaceName(interfaceName 是在url里面的,可以通过 uri 匹配进行流量操控)。
如果要做到基于 header 的流量匹配,还需改动 dubbo sdk。链路追踪和日志等仍需要使用原来dubbo自己的方式。
参考:
dubbo:registry
dubbo:reference