自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Dubbo 同步調(diào)用太慢,也許你可以試試異步處理

開發(fā) 前端
異步調(diào)用配置其實與普通 xml服務(wù)引用配置類似,只不過我們還需要增加一個 dubbo:method將指定方法配置成異步調(diào)用。

[[378981]]

 本文轉(zhuǎn)載自微信公眾號「小黑十一點半」,作者樓下小黑哥 。轉(zhuǎn)載本文請聯(lián)系小黑十一點半公眾號。

Hello,大家好,我是樓下小黑哥~

今天原本是想解析一道朋友在大廠面試的時候碰到問題:

「Dubbo 異步調(diào)用的底層原理是什么?」

之前其實聽說過 Dubbo 異步調(diào)用,但是沒有在實際業(yè)務(wù)中使用過,所以使用方法比較陌生。

再加上 Dubbo 2.7 版本對于異步調(diào)用進行了一些修改,網(wǎng)上找到的一些資料也比較老,所以今天先寫一篇介紹一下 Dubbo 2.7 版本之后的異步調(diào)用使用方式。

后續(xù)我們從源碼出發(fā)再介紹一下 Dubbo 底層原理。

異步調(diào)用

我們平常大部分都是使用 Dubbo 的同步調(diào)用,即調(diào)用 Dubbo 請求之后,調(diào)用線程將會阻塞,直到服務(wù)提供者返回結(jié)果。

那相反,Dubbo 異步調(diào)用就不會阻塞調(diào)用線程,那么在服務(wù)提供者返回結(jié)果這段時間,我們就可以執(zhí)行其他業(yè)務(wù)邏輯。

下面我們從代碼示例,來學(xué)習(xí)一下如何使用 Dubbo 異步調(diào)用。

PS:下面例子 Dubbo 版本為 2.7。

第一種方式

Dubbo 異步調(diào)用是針對方法級別,所以我們需要對引用接口中指定方法做一些專門的配置。

異步調(diào)用配置其實與普通 xml服務(wù)引用配置類似,只不過我們還需要增加一個 dubbo:method將指定方法配置成異步調(diào)用。

示例 xml 配置如下:

  1. <dubbo:reference id="asyncService" interface="org.apache.dubbo.samples.governance.api.AsyncService"
  2.       <dubbo:method name="sayHello" async="true" /> 
  3. </dubbo:reference> 

服務(wù)引用配置完成之后,此時如果直接調(diào)用這個方法,將會立即返回 null,內(nèi)部將會異步執(zhí)行服務(wù)端調(diào)用邏輯。

  1. // 此調(diào)用會立即返回null 
  2. String world = asyncService.sayHello("world"); 

// 畫個時序圖

如果我們需要獲取服務(wù)提供者返回的結(jié)果,那么此時需要借助 RpcContext。這個類是 Dubbo 中專門用于保存 「RPC」 調(diào)用過程中一些關(guān)鍵信息。

因此我們可以借助這個類可以獲取到 「RPC」 很多信息,這次我們主要使用下面的方法獲取 CompletableFuture。

  1. RpcContext.getContext().getCompletableFuture() 

CompletableFuture 是 JDK1.8 之后提供的異步任務(wù)增強類,我們可以直接調(diào)用其 get 方法直接獲取返回結(jié)果。

  1. // 此調(diào)用會立即返回null 
  2. String world = asyncService.sayHello("world"); 
  3. // 拿到調(diào)用的Future引用,當(dāng)結(jié)果返回后,會被通知和設(shè)置到此Future 
  4. CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture(); 
  5. helloFuture.get(); 

這里需要注意一點。調(diào)用get 方法之后,線程就會被阻塞,「直到服務(wù)端返回結(jié)果或者服務(wù)調(diào)用超時」。

另外如果不想線程被阻塞,我們可以使用 whenComplete,添加回調(diào)方法,然后異步處理返回結(jié)果。

  1. // 此調(diào)用會立即返回null 
  2. String world = asyncService.sayHello("world"); 
  3. // 拿到調(diào)用的Future引用,當(dāng)結(jié)果返回后,會被通知和設(shè)置到此Future 
  4. CompletableFuture<String> helloFuture = RpcContext.getContext().getCompletableFuture(); 
  5. // 為Future添加回調(diào) 
  6. helloFuture.whenComplete((retValue, exception) -> { 
  7.     if (exception == null) { 
  8.         System.out.println("return value: " + retValue); 
  9.     } else { 
  10.         exception.printStackTrace(); 
  11.     } 
  12. }); 

從上面的例子我們可以看到, Dubbo 消費端異步調(diào)用借助了JDK 提供的 CompletableFuture,這個類非常強大,提供的方法也非常多。

小黑哥之前寫過一篇文章,比較完整的介紹了 CompletableFuture的用法,感興趣可以深入學(xué)習(xí)一下。

// TODO 文章

上面的方式我們使用 xml引用服務(wù),不過現(xiàn)在很多同學(xué)應(yīng)該直接使用 Dubbo 注解引用服務(wù)。

如果想直接使用注解方式,其實也非常簡單,只要使用 @Method注解即可。

配置方法如下:

  1. @Reference(interfaceClass = AsyncService.class, 
  2.         timeout = 1000, 
  3.         methods = {@Method(name = "sayHello", async = true)}) 
  4. private AsyncService asyncService; 

第二種方式

第一種方式我們還需要額外修改 Dubbo 相關(guān)配置,相對來說比較繁瑣。那第二種方式就不需要做額外配置了,它只要使用 RpcContext#asyncCall就可以直接完成異步調(diào)用。

示例代碼如下:

  1. // 使用  asyncCall 異步調(diào)用 
  2. CompletableFuture<String> f = RpcContext.getContext().asyncCall(() -> asyncService.sayHello("async call request")); 
  3. // get 將會一直阻塞到服務(wù)端返回,或者直到服務(wù)調(diào)用超時 
  4. System.out.println("async call returned: " + f.get()); 
  5.  
  6. // 異步調(diào)用,不關(guān)心服務(wù)端返回 
  7. RpcContext.getContext().asyncCall(() -> { 
  8.     asyncService.sayHello("one way call request1"); 
  9. }); 

這種方式返回依然是 CompletableFuture對象,操作方式就如同第一種方式。

第三種方式

終于到了最后一種方式了,這種方式與上面兩種方式都不太一樣,其完全不需要借助RpcContext就可以完成,開發(fā)流程與普通 Dubbo 服務(wù)一樣。

首先需要服務(wù)提供者事先定義 CompletableFuture 簽名的服務(wù):

  1. public interface AsyncService { 
  2.     CompletableFuture<String> sayHello(String name); 

「注意接口的返回類型是 CompletableFuture?!?/string>

服務(wù)端接口實現(xiàn)邏輯如下:

  1. public class AsyncServiceImpl implements AsyncService { 
  2.     private static Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class); 
  3.  
  4.     @Override 
  5.     public CompletableFuture<String> sayHello(String name) { 
  6.         return CompletableFuture.supplyAsync(() -> { 
  7.             try { 
  8.                 Thread.sleep(10000); 
  9.             } catch (InterruptedException e) { 
  10.                 e.printStackTrace(); 
  11.             } 
  12.             return "async response from provider."
  13.         }); 
  14.     } 
  15.  

服務(wù)端需要使用 CompletableFuture 完成業(yè)務(wù)邏輯。

消費端這時就不需要借助了 RpcContext,可以直接調(diào)用服務(wù)提供者。

  1. // 調(diào)用直接返回CompletableFuture 
  2. CompletableFuture<String> future = asyncService.sayHello("async call request"); 
  3. // 增加回調(diào) 
  4. future.whenComplete((v, t) -> { 
  5.     if (t != null) { 
  6.         t.printStackTrace(); 
  7.     } else { 
  8.         System.out.println("Response: " + v); 
  9.     } 
  10. }); 
  11. // 早于結(jié)果輸出 
  12. System.out.println("Executed before response return."

這種方式對于調(diào)用者來就比較方便,無需引入其他對象,可以像使用同步的方式使用異步調(diào)用。

其他參數(shù)

上面介紹了三種的 Dubbo 異步調(diào)用的使用方式,下面主要介紹一下異步調(diào)用涉及其他參數(shù)。

sent

我們可以在 dubbo:method 設(shè)置:

  1. <dubbo:method name="findFoo" async="true" sent="true" /> 

也可以在注解中設(shè)置:

  1. @Reference(interfaceClass = XXX.class, 
  2.         version = AnnotationConstants.VERSION, 
  3.         timeout = 1000, 
  4.         methods = {@Method(name = "greeting", timeout = 3000, retries = 1, sent = false)}) 

默認情況下sent=false, Dubbo 將會把消息放入 IO 隊列,然后立刻返回。那這時如果宕機,消息就有可能沒有發(fā)送給服務(wù)端。

那如果我們將其設(shè)置成 sent=true,Dubbo 將會等待消息發(fā)送發(fā)出才會返回,否則將會拋出異常。

return

Dubbo 異步調(diào)用默認將會創(chuàng)建 Future 對象,然后設(shè)置到 RpcContext 中。那我們?nèi)绻魂P(guān)心返回值,只想單純的異步執(zhí)行,那我們可以配置 return="false",以此減少 Future 對象的創(chuàng)建和管理成本。

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

總結(jié)

今天的文章介紹三種 Dubbo 異步調(diào)用的使用方式:

第一種需要修改 Dubbo xml 配置文件或者注解,然后再通過 RpcContext獲取異步 Future對象。

第二種無需修改任何配置文件,我們可以直接通過RpcContext#asyncCall異步完成方法調(diào)用,然后獲取異步 Future對象。

第三種無需修改任何配置文件,也無需使用 RpcContext,我們需要定義一個返回值是 CompletableFuture方法,然后服務(wù)端與消費端正常開發(fā)即可。

這三種方式,第三種對于消費者使用起來最方便,不過個人覺得服務(wù)提供者開發(fā)起來比較麻煩。

第二種相當(dāng)于第一種,無需修改配置文件,個人覺得還是比較方便的,所以小黑哥還是傾向于使用第二種方式。

好了,今天的文章就到這里了,下次我們詳細聊聊 Dubbo 異步調(diào)用的原理。

 

責(zé)任編輯:武曉燕 來源: 小黑十一點半
相關(guān)推薦

2009-10-20 16:48:30

C#委托

2022-07-01 08:14:28

Dubbo異步代碼

2009-11-09 10:50:30

WCF異步調(diào)用

2009-12-21 14:10:26

WCF異步調(diào)用

2009-11-06 15:54:15

WCF異步調(diào)用

2009-07-01 13:58:00

JavaScript異

2022-06-17 11:10:43

PandasPolarsPython

2012-10-29 10:59:27

Windows 8

2009-12-07 14:35:42

WCF異步調(diào)用

2011-03-02 08:57:22

jQueryJavaScript

2009-12-07 14:26:47

WCF異步調(diào)用

2010-01-11 17:24:19

VB.NET異步調(diào)用

2021-03-29 09:26:44

SpringBoot異步調(diào)用@Async

2024-07-31 15:57:41

2024-10-15 10:28:43

2020-11-18 19:11:26

iOSFlutterNative

2009-07-01 14:05:23

JavaScript異

2009-07-01 14:23:46

JavaScript異

2009-07-01 14:37:14

JavaScript異

2010-02-22 13:28:05

WCF異步調(diào)用
點贊
收藏

51CTO技術(shù)棧公眾號