Dubbo下一站:Apache顶级项目

导读:
近日,在apache dubbo开发者沙龙杭州站的活动中,阿里巴巴中间件技术专家曹胜利(展图)向开发者们分享了dubbo2.7版本的规划。
本文将为你探秘 dubbo 2.7背后的思考和实现方式。
作者:(按姓氏拼音排序,排名不分先后)
曹胜利(展图):apache dubbo committer。
刘军(陆龟):apache dubbo committer。
dubbo 2.7 将围绕 异步支持优化、元数据改造,引入jdk8的特性、netty4.0的特性以及metricsapi 5个方面提升服务调用和服务治理的效率,以及可扩展性,同时将修复社区提出的若干问题。
据悉,2.7.x会作为dubbo在apache社区的毕业版本,dubbo将有机会成为继rocketmq后,来自阿里巴巴的又一个apache顶级项目(tlp)。
优化对异步的支持基于dubbo实现全异步编程,是在2.7.0版本中对现有异步方式增强后新引入的功能。之前的版本对异步支持用起来不是很友好,存在若干问题,2.7版本将基于jdk8 中的completablefuture做出一些针对性的增强,同时新增了@dubboasync的注解,通过这个注解可以生成异步化相关的代码。
» 2.6.x版本之前的异步方式
在2.6.x及之前的版本提供了一定的异步编程能力,包括consumer端异步调用、参数回调、事件通知等。但当前的异步方式存在以下问题:
future获取方式不够直接;
future接口无法实现自动回调,而自定义responsefuture虽支持回调但支持的异步场景有限,如不支持future间的相互协调或组合等;
不支持provider端异步
以consumer端异步使用方式为例:
1、定义一个普通的同步接口并声明支持异步调用
public interface fooservice {string findfoo(string name);}   2、通过rpccontext获取future
// 此调用会立即返回nullfooservice.findfoo(fooid);// 拿到调用的future引用,当结果返回后,会被通知和设置到此futurefuture foofuture = rpccontext.getcontext().getfuture();foofuture.get();或
// 此调用会立即返回nullfooservice.findfoo(fooid);// 拿到dubbo内置的responsefuture并设置回调responsefuture future = ((futureadapter)rpccontext.getcontext().getfuture()).getfuture();future.setcallback(new responsecallback() {@overridepublic void done(object response) {    system.out.print(response);}@overridepublic void caught(throwable exception) {    exception.printstacktrace();}});从这个简单的示例我们可以体会到一些使用中的不便之处:
findfoo的同步接口,不能直接返回代表异步结果的future,通过rpccontext进一步获取。
future只支持阻塞式的get()接口获取结果。
通过获取内置的responsefuture接口,可以设置回调。但获取responsefuture的api使用不便,且仅支持设置回调其他异步场景均不支持,如多个future协同工作的场景等。
» 2.7.0基于completablefuture的增强
了解java中future演进历史的同学应该知道,dubbo 2.6.x及之前版本中使用的future是在java 5中引入的,所以存在以上一些功能设计上的问题,而在java 8中引入的completablefuture进一步丰富了future接口,很好的解决了这些问题。
dubbo在2.7.0版本已经升级了对java 8的支持,同时基于completablefuture对当前的异步功能进行了增强。
1、支持直接定义返回completablefuture的服务接口。通过这种类型的接口,我们可以更自然的实现consumer、provider端的异步编程。
public interface asyncservice {completablefuture sayhello(string name);}2、如果你不想将接口的返回值定义为future类型,或者存在定义好的同步类型接口,则可以额外定义一个异步接口并提供future类型的方法。
public interface greetingsservice {string sayhi(string name);}@asyncfor(greetingsservice.class)public interface grettingserviceasync extends greetingsservice {completablefuture sayhiasync(string name);}这样,provider可以只实现sayhi方法;而consumer通过直接调用sayhiasync可以拿到一个future实例,dubbo框架在provider端会自动转换为对sayhi方法的调用。为每个同步方法提供一个异步方法定义会比较麻烦,更进一步的,利用dubbo生态中的annotationprocessor实现,可以自动帮我们自动生成异步方法定义。
3、同样的,如果你的原始接口定义不是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;}}在方法体的开始rpccontext.startasync()启动异步,并开启新线程异步的执行业务逻辑,在耗时操作完成后通过asynccontext.write将结果写回。
4、rpccontext直接返回completablefuture
completablefuture f = rpccontext.getcontext().getcompletablefuture();以上所有的增强,是在兼容已有异步编程的基础上进行的,因此基于2.6.x版本编写的异步程序不用做任何改造即可顺利运行。
元数据改造元数据的改造主要是从适配微服务注册中心、配置中心分离的模型、减轻注册中心压力、提高服务治理能力和效率的角度来执行的。目前版本的dubbo在注册中心的url有数十个key/value的键值对,包含了一个服务的所有元数据。在大规模实践的基础上,我们逐渐发现这样组织的元数据存在一些问题:
注册中心存储的url过长:
导致存储压力骤增,变更事件的推送效率明显下降;同时给订阅方带来了额外的计算压力,尤其是大规模场景下的内存,增长显著。
注册中心承担了过多服务治理配置的功能:
负责初始配置的同步,同时负责存储各种运行期配置规则。这一方面加剧了注册中心的压力,另一方面配置规则的灵活性也受到了一定的限制,同时也无法利用一些更专业的微服务配置中心带来的强大功能。
属性的功能定位不清晰:
methods, pid, owner看起来都是为服务查询服务而注册的属性,但当我们实际开发或操作服务管控系统时,却发现这样简陋的信息是很难满足查询治理需求的。我们更多的属性,需要更丰富的注册数据。以methods为例,虽然方法列表的内容已经很长了,但当我们要在ops开发服务测试/mock功能时,却发现需要的方法签名等数据还是无法获取。
概括以上问题,我们将url中的元数据划分了三个部分:
元数据信息
接口的完整定义:包含接口名,接口所含的方法,以及方法所含的出入参信息。对于服务测试和服务mock有非常重要的作用。
执行链路上数据
需要将参数从provider端传递给消费者端,让消费者端感知到的。如token,timeout等。
服务自持有配置&ops需求
只有在provider端或者消费者端需要使用的,如executes, document等。
支持配置中心配置中心是dubbo.properties的动态版本,支持的粒度包括全局的、应用级别的和服务级别的等维度。通过上面的元数据改造,配置中心支持,再加上原有的注册中心,dubbo体系里就会存在:
注册中心:
理想情况下,注册中心将只用于关键服务信息(核心链路)的同步,进一步减轻注册中心的存储压力,提高地址同步效率,同时缓解当前由于url冗余在大规模推送时造成的consumer端内存计算压力。
配置中心:
解决当前配置和地址信息耦合的问题,通过抽象动态配置层,让开发者可以对接微服务场景下更常用的、更专业的配置中心,如nacos, apollo, consul, etcd等;提供更灵活的、更丰富的配置规则,包括服务、应用不同粒度的配置,更丰富的路由规则,集中式管理的动态参数规则等。
服务查询治理中心(含元数据)
对于纯粹的服务查询相关的数据,包括consumer的服务订阅数据,往往都是注册后不可变的并且不需要节点间的同步,如当前url可以看到的methods、owner等key以及所有的consumer端url。
因此我们在2.7.0中引入了存储模块,专门用来存放这部分数据,这部分将会和新版本的dubbo-ops密切整合,作为丰富的服务查询、测试等功能的数据基础,因此这部分的数据将会得到进一步的丰富。总体来说否开启此功能对用户将是可选的,并且实现上也将是可扩展的,如我们计划支持redis, zookeeper等。
路由规则
dubbo 提供了具有一定扩展性的路由规则,其中具有代表性的是条件路由和脚本路由。2.6.x及以下版本存在的问题:
路由规则存储在注册中心
只支持服务粒度的路由,应用级别无法定义路由规则
支持路由缓存,但基本不具有扩展性
一个服务或应用允许定义多条路由规则,服务治理无法管控
实现上,每条规则生成一个router实例并动态加载
从问题出发我们重新设计,将原来的路由配置从注册中心迁往配置中心。明确了配置和服务发现的边界。新增了routerchain,用于重构路由规则逻辑,新增应用级别路由,tag路由优化等。针对服务级别的路由,精确到单个服务,避免了无法明确路由规则的问题。
我们简单概括下各个类的协作关系。
registrydirectory,包含完整的地址列表,直接对接注册中心,并动态接收注册中心地址变更。
routerchain,由router组装成的列表,是路由动作的入口,接收传入的地址列表并将过滤后的地址列表返回给调用方,而具体的过滤动作则委托给router执行
router,接收并解析路由规则,接收地址列表,根据路由规则完成过滤动作,并返回过滤后的地址列表。其本身也是一个configurationlistener,随时接收路由规则更新。
configurationlistener,动态配置变更的回调接口
dynamicconfiguration,动态配置spi,支持的扩展实现包括zookeeper、apollo、nacos等
dubbo 将在近期正式发布2.7.0版本,恰值dubbo宣布重启一周年。这一年,dubbo 共发布了13个版本,社区共有24位ppmc/committer,144位contributor,在北京、上海、深圳、成都和杭州举办了5场开发者沙龙,但技术开源的道路并没有止境,我们欢迎更多的开发者们可以参与进来,并到dubbo meetup来进行分享,一起建设dubbo生态。

华为看好旗下最新的P30系列新旗舰,备货量将高达1600万部
野小兽代言人刘涛618直播大秀,揭秘好身材背后的秘密
微型服务器需求将在未来3-5年显著提升
发动机包含了哪些传感器
realme真我GT即将发布,搭载高通骁龙888芯片
Dubbo下一站:Apache顶级项目
OcleanSE青春版评测 整体刷牙体验十分出色
igbt反向并联二极管作用
LiFi新技术实现光照上网,理论网速已超WiFi百倍
欧玛执行器在未来的发展趋向将会是怎样的
小米11备货多,三星2K 120Hz屏
const在C语言与C++中的区别与使用!
顶级上市业务领导者加入Sumo Logic
若高通成功收购恩智浦,将给行业带来哪些影响?
如何制作Wi-Fi控制的四轮机器人
集成多路复用输入ADC可减少诸多难题
巡检机器人提高了城市地下综合管廊的运维和运营水平
思科大型发布会上宣布了一系列新的硬件,软件和芯片产品
三星Chromebook Pro怎么样?三星Chromebook Pro上手图赏
如何通过Arduino制作数字示波器