Dubbo下一站:Apache顶级项目

 导读:

近日,在Apache Dubbo开发者沙龙杭州站的活动中,阿里巴巴中间件技术专家曹胜利(展图)向开发者们分享了Dubbo2.7版本的规划。

本文将为你探秘 Dubbo 2.7背后的思考和实现方式。

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的注解,通过这个注解可以生成异步化相关的代码。

_2018_12_04_10_28_50

» 2.6.x版本之前的异步方式

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

Future获取方式不够直接;

Future接口无法实现自动回调,而自定义ResponseFuture虽支持回调但支持的异步场景有限,如不支持Future间的相互协调或组合等;

不支持Provider端异步

以Consumer端异步使用方式为例:

1、定义一个普通的同步接口并声明支持异步调用

public interface FooService { String findFoo(String name);}  <dubbo:reference id="fooService" interface="com.alibaba.foo.FooService">   <dubbo:method name="findFoo" async="true" /> </dubbo:reference> 

2、通过RpcContext获取Future

// 此调用会立即返回nullfooService.findFoo(fooId);// 拿到调用的Future引用,当结果返回后,会被通知和设置到此FutureFuture<Foo> fooFuture = RpcContext.getContext().getFuture();fooFuture.get(); 

// 此调用会立即返回nullfooService.findFoo(fooId);// 拿到Dubbo内置的ResponseFuture并设置回调ResponseFuture future = ((FutureAdapter)RpcContext.getContext().getFuture()).getFuture();future.setCallback(new ResponseCallback() { @Override public void done(Object response) {     System.out.print(response); }  @Override public 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<String> sayHello(String name);} 

2、如果你不想将接口的返回值定义为Future类型,或者存在定义好的同步类型接口,则可以额外定义一个异步接口并提供Future类型的方法。

public interface GreetingsService { String sayHi(String name);}  @AsyncFor(GreetingsService.class)public interface GrettingServiceAsync extends GreetingsService { CompletableFuture<String> 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 
                    
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信