Dubbo异步调用

发布时间 2023-08-24 18:32:11作者: JaxYoun

Dubbo异步调用

原文出处:https://www.cnblogs.com/weir110/p/17455749.html

一、前言

“异步”作为性能优化的利器之一,对于系统优化是一种常见思路;Dubbo天然的异步模式,不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。本文将针对Dubbo 异步使用展开介绍。

img

二、使用模式

Dubbo 异步调用

在 Dubbo 中服务调用方和服务提供方都支持异步调用,其调用模式可以组合为以下四种:

1.Consumer同步 - Provider同步
2.Consumer异步 - Provider同步
3.Consumer同步 - Provider异步
4.Consumer异步 - Provider异步

Provider端异步执行将阻塞的业务从Dubbo内部线程池切换到业务自定义线程,避免Dubbo线程池的过度占用,有助于避免不同服务间的互相影响。异步执行无异于节省资源或提升RPC响应性能,因为如果业务执行需要阻塞,则始终还是要有线程来负责执行。

三、使用方式

3.1 使用CompletableFuture签名的接口

  1. 服务端-接口声明 CompletableFuture
public interface AsyncService {
    CompletableFuture<String> sayHello(String name);
}
  1. 服务端-接口实现:
public class AsyncServiceImpl implements AsyncService {
    @Override
    public CompletableFuture<String> sayHello(String name) {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println(name);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return "async response from provider.";
        });
    }
}

通过 return CompletableFuture.supplyAsync() ,业务执行已从Dubbo线程切换到业务线程,避免了对Dubbo线程池的阻塞。

  1. 客户端-接口引入
<dubbo:reference id="asyncService" timeout="10000" interface="com.alibaba.dubbo.samples.async.api.AsyncService"/>
  1. 客户端-接口调用
// 调用直接返回CompletableFuture
CompletableFuture<String> 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.");

3.2 使用AsyncContext

  1. 客户端-接口引入
<dubbo:reference id="asyncService" interface="org.apache.dubbo.samples.governance.api.AsyncService">
      <dubbo:method name="sayHello" async="true" />
</dubbo:reference>
  1. 客户端-接口调用
// 此调用会立即返回null
asyncService.sayHello("world");
// 拿到调用的Future引用,当结果返回后,会被通知和设置到此Future
CompletableFuture<String> helloFuture = RpcContext.getServiceContext().getCompletableFuture();
// 为Future添加回调
helloFuture.whenComplete((retValue, exception) -> {
    if (exception == null) {
        System.out.println(retValue);
    } else {
        exception.printStackTrace();
    }
});

或者,也可以这样做异步调用

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

future.get();

四、发送模式

异步总是不等待返回,你也可以设置是否等待消息发出

  • sent="true" 等待消息发出,消息发送失败将抛出异常。
  • sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。
<dubbo:method name="findFoo" async="true" sent="true" />

如果你只是想异步,完全忽略返回值,可以配置 return="false",以减少 Future 对象的创建和管理成本

<dubbo:method name="findFoo" async="true" return="false" />

img

参考

阅读文献

代码案例

https://gitee.com/will-we/dubbo-blog/tree/main/2-advanced/dubbo-async