Dubbo异步调用(七)

1、参考

异步调用:http://dubbo.apache.org/en-us/docs/user/demos/async-call.html

2、异步调用

2.1、Dubbo2.0.6+的异步调用

这里说的异步调用应该是非阻塞的NIO调用,一个线程可同时并发调用多个远程服务,每个服务的调用都是非阻塞的,线程立即返回。

Dubbo异步调用(七)_第1张图片

上图中主要关注一下userThread的行为,用户发出调用后,IOThread会在上下文中设置Future。用户从RpcContext中取得Future,然后wait这个Future其它的事情都由IOThread完成。

总之,用户发出调用后会立刻返回,而不是调用在服务端执行完代码、返回结果后返回。用户返回后可以去做点其它事情,比如调用另外一个服务,然后回头等待前一个调用完成。从上图可以看出,异步调用完全是Consumer端的行为。

配置:


      


      

async=true表示异步调用,可以看到配置发生在Consumer端,能精确到方法。

方法异步调用后,Consumer端的代码写法:

// 此方法应该返回Foo,但异步后会立刻返回NULL
fooService.findFoo(fooId);
// 立刻得到当前调用的Future实例,当发生新的调用时这个东西将会被覆盖
Future fooFuture = RpcContext.getContext().getFuture();

// 调用另一个服务的方法
barService.findBar(barId);
// 立刻得到当前调用的Future
Future barFuture = RpcContext.getContext().getFuture();

// 此时,两个服务的方法在并发执行
// 等待第一个调用完成,线程会进入Sleep状态,当调用完成后被唤醒。
Foo foo = fooFuture.get();
// 同上
Bar bar = barFuture.get();
// 假如第一个调用需要等待5秒,第二个等待6秒,则整个调用过程完成的时间是6秒。

理解的状态是要有一个多路复用器,同时等待所有的调用,谁就绪就处理谁。Dubbo中是按顺序等待,如果后边的调用已经调用完成,前边的没有完成,那么后边的调用会被前边的卡住,得不到及时处理。

配置是否等待IOThread发送完Request后再返回:

  • sent="true" ,等待请求发送出去后再往回,如果发送失败直接抛出异常。
  • sent="false" ,将调用交给IOThread后立即返回。实际这个时候请求进入到IOThread的队列,排除等着被发送出去。

如果对返回结果没有兴趣:

2.2、Dubbo2.7.0之后的异步调用

从v2.7.0开始,Dubbo的所有异步编程接口开始以CompletableFuture为基础,感觉这种方式还不成熟,官方文档也没什么资料,很多重要问题没有说明,看一下就好了。

服务端接口的定义要改变,主要指返回值类型:

public interface AsyncService {
    CompletableFuture sayHello(String name);
}

Consumer端引用服务:

// 调用直接返回CompletableFuture
CompletableFuture future = asyncService.sayHello("async call request");
// 增加回调
future.whenComplete((v, t) -> {
    if (t != null) {
        t.printStackTrace();
    } else {
        System.out.println("Response: " + v);
    }
});
// 早于结果输出
System.out.println("Executed before response return.");

调用发起后,立刻得到一个future。然后通过Lamda表达式向此future增加回调。将远程接口真正返回后,由此回调处理返回结果。

这里有一个问题没讲明白,回调的执行必然不是当前线程,Consumer部应该也会配置一个线程池,由线程池里边的线程执行回调应该。

上边的异步调用没有涉及到RpcContext,另外一个异步调用的方法就是使用RpcContext,与上边方法的区别在于Consumer端的配置与代码,这种风格与旧版本非常像。

配置:


      

代码:

// 此调用会立即返回null
asyncService.sayHello("world");
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
CompletableFuture helloFuture = RpcContext.getContext().getCompletableFuture();
// 为Future添加回调
helloFuture.whenComplete((retValue, exception) -> {
    if (exception == null) {
        System.out.println(retValue);
    } else {
        exception.printStackTrace();
    }
});

还有一种方法:

CompletableFuture future = RpcContext.getContext().asyncCall(
    () -> {
        asyncService.sayHello("oneway call request1");
    }
);

future.get();

 

你可能感兴趣的:(Dubbo)