Dubbo實戰篇--異步

theme: cyanosis
日期 更新說明
2023年6月3日 初版編輯

最是人間留不住,朱顏辭鏡花辭樹

離開這段時間,發現Dubbo其實已經已經發布到了3.2了,其實有點斷更。

前言

“異步”作爲性能優化的利器之一,對於系統優化是一種常見思路;Dubbo天然的異步模式,不需要啓動多線程即可完成並行調用多個遠程服務,相對多線程開銷較小。本文將針對Dubbo 異步使用展開介紹。

使用

Dubbo 異步調用

在 Dubbo 中服務調用方和服務提供方都支持異步調用,其調用模式可以組合爲以下四種:

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

Provider端異步執行將阻塞的業務從Dubbo內部線程池切換到業務自定義線程,避免Dubbo線程池的過度佔用,有助於避免不同服務間的互相影響。異步執行無異於節省資源或提升RPC響應性能,因爲如果業務執行需要阻塞,則始終還是要有線程來負責執行。

使用方式

使用 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. XML 引用服務
<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.");

使用 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章