dubbo源码解析(四十三)2.7新特性

8次阅读

共计 4200 个字符,预计需要花费 11 分钟才能阅读完成。

DUBBO——2.7 大揭秘
目标:了解 2.7 的新特性,以及版本升级的引导。
前言
我们知道 Dubbo 在 2011 年开源,停止更新了一段时间。在 2017 年 9 月 7 日,Dubbo 悄悄的在 GitHub 发布了 2.5.4 版本。随后,版本发布的非常迅速,Dubbo 项目被重启了,经过大半年的更新,在 2018 年 2 月 15 日,Dubbo 获得了 14 张赞成票,在无弃权和反对票的情况下,正式通过投票,顺利成为 Apache 基金会孵化项目。现在的 Dubbo 社区非常活跃,版本进度也非常的快。

从上图就可以看出 dubbo 现在的活跃度。
现在 dubbo 项目有以下几个分支:

2.5.x:该分支在近期投票决定不再维护。
2.6.x:该分支现在还在维护中,包名前缀是 com.alibaba,也是贡献给 Apache 之前的版本。
2.7.1-release:一个临时分支。
3.x-dev:将以 Streaming 为内核,重点的改变在服务治理和编程模型上。具体我也还没有深入研究,我也会跟踪该分支的变动,敬请期待吧。
master:目前版本是 2.7.x,包名前缀是:org.apache,也是 Dubbo 贡献给 Apache 的开发版本,接下来的分析也会在 2.7.1 上进行分析。

关注 dubbo 社区的朋友应该也知道在 2019.3.23 在南京举办了 Meetup,其中有一个专题就是讲 2.7 新特性介绍。我就在分享者的基础上讲解一下自己的理解。
正文
(一)JDK 版本
在所需的最小 JDK 版本从以前的 1.6 变成了 1.8。
(二) 包重命名
com.alibaba.dubbo – > org.apache.dubbo
(三) 异步支持优化
我们知道 dubbo 协议本身支持三种发送请求方式:

单向发送:执行方法不需要返回结果
同步发送:执行方法后,等待结果返回,否则一直阻塞.

异步发送:也就是当我发送调用后,我不阻塞等待结果,直接返回,将返回的 future 保存到上下文,方便后期使用。在异步发送中有两种方式分别是

future:当请求有响应后,通过 future.get() 来获得响应结果,但是 future.get() 会导致线程阻塞,future 从 RpcContext 获取。
callback:设置一个回调线程,当接收到响应时,自动执行,不会对当前线程造成阻塞,自定义 ResponseFuture 支持 callback。

2.6.x 版本的异步方式提供了一些异步能力,包括 Consumer 端异步调用、参数回调、事件通知等。但当前的异步方式存在以下问题:

Future 获取方式不够直接,只能在 RpcContext 中进行获取;
Future 只支持阻塞式的 get() 接口获取结果。
Future 接口无法实现自动回调,而自定义 ResponseFuture 虽支持 callback 回调但支持的异步场景有限,如不支持 Future 间的相互协调或组合等;
不支持 Provider 端异步

具体的可以参考该文章 dubbo 源码解析(二十四)远程调用——dubbo 协议中的源码分析来理解其中存在的问题。
那么在 2.7.x 版本,由于 JDK 版本升级到了 1.8,引入了 JDK1.8 中的 CompletableFuture 接口,CompletableFuture 支持 future 和 callback 两种调用方式。关于 CompletableFuture 怎么被运用到 dubbo 中我会在后续的文章介绍。引入该接口后,做了以下优化:

支持 Provider 端异步
支持直接定义返回 CompletableFuture 的服务接口。通过这种类型的接口,我们可以更自然的实现 Consumer、Provider 端的异步编程。

public interface AsyncService {
CompletableFuture<String> sayHello(String name);
}
如果你不想将接口的返回值定义为 Future 类型,或者存在定义好的同步类型接口,则可以额外定义一个异步接口并提供 Future 类型的方法。
public interface GreetingsService {
String sayHi(String name);
}
@AsyncFor(GreetingsService.class)
public interface GrettingServiceAsync extends GreetingsService {
CompletableFuture<String> sayHiAsync(String name);
}
如果你的原始接口定义不是 Future 类型的返回值,Provider 端异步也提供了类似 Servlet3.0 里的 Async Servlet 的编程接口: RpcContext.startAsync()

public interface AsyncService {
String sayHello(String name);
}
public class AsyncServiceImpl implements AsyncService {
public String sayHello(String name) {
final AsyncContext asyncContext = RpcContext.startAsync();
new Thread(() -> {
asyncContext.write(“Hello ” + name + “, response from provider.”);
}).start();
return null;
}
}
异步过滤器链回调。
具体的实现原理我在后续文章中结合源码来讲解,注意:这些改动都仅仅支持 dubbo 协议。
(四) 元数据改造
我们知道 2.7 以前的版本只有注册中心,注册中心的 URL 有数十个 key/value 的键值对,包含了一个服务所有的元数据。在越来越多的功能被增加,元数据也变得异常庞大,就出现了下面的问题:

注册中心存储的 URL 过长:这会导致存储的压力骤增,数据庞大导致在修改元数据后的通知效率也下降,并且增加了消费者对于元数据解析的压力,尤其是在大规模场景下的内存增长显著
注册中心承担了过多的服务治理配置的功能:初始配置的同步、存储各种运行期配置规则加剧了注册中心的压力,配置规则的灵活性也有所限制,阻碍了市场上的一些优秀微服务配置中心的集成和扩展。
属性的功能定位不清晰:methods,pid,owner 虽然是为了查询服务而注册的属性,但是这些简陋的信息很难满足查询服务治理需求,所以需要更加丰富的注册数据。例如 methods,虽然方法列表的内容已经很长,但是在 ops 开发服务测试 /mock 功能时,发现需要的方法签名等数据还是无法获取。

针对以上问题,在 2.7 中,将 URL 中的元数据划分了三个部分:

元数据信息:接口的完整定义,包含接口名,接口所含的方法,以及方法所含的出入参信息。对于服务测试和服务 mock 有很重要作用。
执行链路上数据:需要将参数从 provider 端传递给 consume 端,让 consume 端感知的到,比如 token、timeout 等
服务自己持有的配置 &Ops 需求:只有 provider 端自己需要或者 consume 端自己需要的数据,比如 executes、document 等

改造后,分别形成三大中心:

注册中心:理想情况下,注册中心将只用于关键服务信息(核心链路)的同步,进一步减轻注册中心的存储压力,提高地址同步效率,同时缓解当前由于 URL 冗余在大规模推送时造成的 Consumer 端内存计算压力。
配置中心:解决当前配置和地址信息耦合的问题,通过抽象动态配置层,让开发者可以对接微服务场景下更常用的、更专业的配置中心,如 Nacos, Apollo, Consul, Etcd 等;提供更灵活的、更丰富的配置规则,包括服务、应用不同粒度的配置,更丰富的路由规则,集中式管理的动态参数规则等
服务查询治理中心:对于纯粹的服务查询相关的数据,包括 Consumer 的服务订阅数据,往往都是注册后不可变的并且不需要节点间的同步,如当前 URL 可以看到的 methods、owner 等 key 以及所有的 Consumer 端 URL,目前支持 redis(推荐),zookeeper, 将作为 Dubbo-Admin 支持的服务测试,模拟和其他服务治理功能的基础。

(五) 服务治理规则增强
路由规则的增强
Dubbo 提供了具有一定扩展性的路由规则,其中具有代表性的是条件路由和脚本路由。2.6.x 及以下版本存在的问题:

路由规则存储在注册中心
只支持服务粒度的路由,应用级别无法定义路由规则
支持路由缓存,但基本不具有扩展性
一个服务或应用允许定义多条路由规则,服务治理无法管控
实现上,每条规则生成一个 Router 实例并动态加载

在 2.7.x 版本中,对路由规则做了增强:

丰富的路由规则。

条件路由:支持应用程序级别和服务级别条件。
标记路由:新引入以更好地支持流量隔离,例如灰色部署

配置中心对服务治理的加成

将治理规则与注册表分离,也就是出现了配置中心,使配置中心更容易扩展。有 Apollo 和 Zookeeper,2.7.1 还支持了 consul 和 etcd。
应用程序级动态配置支持。
使用 YAML 作为配置语言,更易于阅读和使用

(六) 新增配置中心
配置中心(v2.7.0)在 Dubbo 中承担两个职责:

外部化配置:启动配置的集中式存储(简单理解为 dubbo.properties 的外部化存储)外部化配置目的之一是实现配置的集中式管理,这部分业界已经有很多成熟的专业配置系统如 Apollo, Nacos 等,Dubbo 所做的主要是保证能配合这些系统正常工作。外部化配置和其他本地配置在内容和格式上并无区别,可以简单理解为 dubbo.properties 的外部化存储,配置中心更适合将一些公共配置如注册中心、元数据中心配置等抽取以便做集中管理
服务治理:服务治理规则的存储与通知。

配置的操作可以查看官方文档,由于现在 dubbo 支持多种配置方式,所以这里需要强调的是配置覆盖的优先级,从上至下优先级依此降低:

(七) 序列化扩展
新增了 Protobuf 序列化支持。
(八) 其他
其他的 bug 修复以及一些小细节优化请查看 github 上的 Issues 或者 PR。
后记
升级 2.7.0 的引导请查看以下链接:http://dubbo.apache.org/zh-cn…

该文章讲解了 dubbo2.7 的新特性,现在 2.7.1 已经发布,有兴趣的可以去看看 2.7.1 新增了什么。下一篇我就先从源码的角度来讲讲这个异步化的改造。

正文完
 0