<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 4683字,需瀏覽 10分鐘

           ·

          2021-01-28 11:30

          點(diǎn)擊藍(lán)色「小黑十一點(diǎn)半關(guān)注樓下小黑哥??

          點(diǎn)擊下方卡片可搜索文章??

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

          今天原本是想解析一道朋友在大廠面試的時(shí)候碰到問(wèn)題:

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

          之前其實(shí)聽(tīng)說(shuō)過(guò) Dubbo 異步調(diào)用,但是沒(méi)有在實(shí)際業(yè)務(wù)中使用過(guò),所以使用方法比較陌生。

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

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

          異步調(diào)用

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

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

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

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

          第一種方式

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

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

          示例 xml 配置如下:

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

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

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

          // 畫個(gè)時(shí)序圖

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

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

          RpcContext.getContext().getCompletableFuture()

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

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

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

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

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

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

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

          // TODO 文章

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

          如果想直接使用注解方式,其實(shí)也非常簡(jiǎn)單,只要使用 @Method注解即可。

          配置方法如下:

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

          第二種方式

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

          示例代碼如下:

          //?使用??asyncCall?異步調(diào)用
          CompletableFuture?f?=?RpcContext.getContext().asyncCall(()?->?asyncService.sayHello("async?call?request"));
          //?get?將會(huì)一直阻塞到服務(wù)端返回,或者直到服務(wù)調(diào)用超時(shí)
          System.out.println("async?call?returned:?"?+?f.get());

          //?異步調(diào)用,不關(guān)心服務(wù)端返回
          RpcContext.getContext().asyncCall(()?->?{
          ????asyncService.sayHello("one?way?call?request1");
          });

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

          第三種方式

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

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

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

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

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

          public?class?AsyncServiceImpl?implements?AsyncService?{
          ????private?static?Logger?logger?=?LoggerFactory.getLogger(AsyncServiceImpl.class);

          ????@Override
          ????public?CompletableFuture?sayHello(String?name)?{
          ????????return?CompletableFuture.supplyAsync(()?->?{
          ????????????try?{
          ????????????????Thread.sleep(10000);
          ????????????}?catch?(InterruptedException?e)?{
          ????????????????e.printStackTrace();
          ????????????}
          ????????????return?"async?response?from?provider.";
          ????????});
          ????}

          }

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

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

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

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

          其他參數(shù)

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

          sent

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

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

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

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

          默認(rèn)情況下sent=false, Dubbo 將會(huì)把消息放入 IO 隊(duì)列,然后立刻返回。那這時(shí)如果宕機(jī),消息就有可能沒(méi)有發(fā)送給服務(wù)端。

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

          return

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

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

          總結(jié)

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

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

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

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

          這三種方式,第三種對(duì)于消費(fèi)者使用起來(lái)最方便,不過(guò)個(gè)人覺(jué)得服務(wù)提供者開(kāi)發(fā)起來(lái)比較麻煩。

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

          好了,今天的文章就到這里了,下次我們?cè)敿?xì)聊聊 Dubbo 異步調(diào)用的原理。

          最后有問(wèn)題可以加我微信,一起討論成長(zhǎng)!


          往期精彩回顧




          有些線程跑著跑著就不見(jiàn)了
          這個(gè)面試官不講套路,怎么上來(lái)就問(wèn)個(gè)架構(gòu)問(wèn)題|面經(jīng)分享
          抄答案就是了,兩套詳細(xì)的設(shè)計(jì)方案,解決頭疼的掉單問(wèn)題|文末又又送書


          瀏覽 91
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧洲精品成人99 | 日本在线视频区区 | 91九色TS另类国产人妖 | 国产免费九九视频 | 黄色直播在线观看 |