theme: cyanosis
日期 | 更新說明 |
---|---|
2023年6月3日 | 初版編輯 |
最是人間留不住,朱顏辭鏡花辭樹
離開這段時間,發現Dubbo其實已經已經發布到了3.2了,其實有點斷更。
前言
“異步”作爲性能優化的利器之一,對於系統優化是一種常見思路;Dubbo天然的異步模式,不需要啓動多線程即可完成並行調用多個遠程服務,相對多線程開銷較小。本文將針對Dubbo 異步使用展開介紹。
使用
Dubbo 異步調用
在 Dubbo 中服務調用方和服務提供方都支持異步調用,其調用模式可以組合爲以下四種:
- Consumer同步 - Provider同步
- Consumer異步 - Provider同步
- Consumer同步 - Provider異步
- Consumer異步 - Provider異步
Provider端異步執行將阻塞的業務從Dubbo內部線程池切換到業務自定義線程,避免Dubbo線程池的過度佔用,有助於避免不同服務間的互相影響。異步執行無異於節省資源或提升RPC響應性能,因爲如果業務執行需要阻塞,則始終還是要有線程來負責執行。
使用方式
使用 CompletableFuture 簽名的接口
- 服務接口的調用添加
CompletableFuture
public interface AsyncService {
CompletableFuture<String> sayHello(String name);
}
- 服務接口實現接口:
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 線程池的阻塞。
- XML 引用服務
<dubbo:reference id="asyncService" timeout="10000" interface="com.alibaba.dubbo.samples.async.api.AsyncService"/>
- 調用遠程服務
// 調用直接返回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.");
使用 AsyncContext
在 consumer.xml 中配置
<dubbo:reference id="asyncService" interface="org.apache.dubbo.samples.governance.api.AsyncService">
<dubbo:method name="sayHello" async="true" />
</dubbo:reference>
調用代碼
// 此調用會立即返回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" />
參考
閱讀文獻
代碼案例
https://gitee.com/will-we/dubbo-blog/tree/main/2-advanced/dubbo-async