<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數(shù)據(jù)包...

          共 4122字,需瀏覽 9分鐘

           ·

          2022-06-08 17:19

          hello,大家好呀,我是小樓!

          今天給大家?guī)硪黄P(guān)于Dubbo IO交互的文章,本文是一位同事所寫,用有趣的文字把枯燥的知識點寫出來,通俗易懂,非常有意思,所以迫不及待找作者授權(quán)然后分享給大家:


          一些有趣的問題

          Dubbo是一個優(yōu)秀的RPC框架,其中有錯綜復(fù)雜的線程模型,本篇文章筆者從自己淺薄的認(rèn)知中,來剖析Dubbo的整個IO過程。在開始之前,我們先來看如下幾個問題:

          • 業(yè)務(wù)方法執(zhí)行之后,數(shù)據(jù)包就發(fā)出去了嗎?
          • netty3和netty4在線程模型上有什么區(qū)別?
          • 數(shù)據(jù)包到了操作系統(tǒng)socket buffer,經(jīng)歷了什么?
          • Provider打出的log耗時很小,而Consumer端卻超時了,怎么可以排查到問題?
          • 數(shù)據(jù)包在物理層是一根管道就直接發(fā)過去嗎?
          • Consumer 業(yè)務(wù)線程await在Condition上,在哪個時機被喚醒?
          • ……

          接下來筆者將用Dubbo2.5.3 作為Consumer,2.7.3作為Provider來講述整個交互過程,筆者站在數(shù)據(jù)包視角,用第一人稱來講述,系好安全帶,我們出發(fā)咯。

          有意思的旅行

          1、Dubbo2.5.3 Consumer端發(fā)起請求

          我是一個數(shù)據(jù)包,出生在一個叫Dubbo2.5.3 Consumer的小鎮(zhèn),我的使命是是傳遞信息,同時也喜歡出門旅行。

          某一天,我即將被發(fā)送出去,據(jù)說是要去一個叫Dubbo 2.7.3 Provider的地方。

          這一天,業(yè)務(wù)線程發(fā)起發(fā)起方法調(diào)用,在FailoverClusterInvoker#doInvoke我選擇了一個Provider,然后經(jīng)過各種Consumer Filter,再經(jīng)過Netty3的pipeline,最后通過NioWorker#scheduleWriteIfNecessary方法,我來到了NioWorker的writeTaskQueue隊列中。

          當(dāng)我回頭看主線程時,發(fā)現(xiàn)他在DefaultFuture中的Condition等待,我不知道他在等什么,也不知道他要等多久。

          我在writeTaskQueue隊列排了一會隊,看到netty3 IO worker線程在永不停歇的執(zhí)行run方法,大家都稱這個為死循環(huán)。

          最后,我很幸運,NioWorker#processWriteTaskQueue選擇了我,我被寫到操作系統(tǒng)的Socket緩沖區(qū),我在緩沖區(qū)等待,反正時間充足,我回味一下今天的旅行,期間我輾轉(zhuǎn)了兩個旅行團,分別叫主線程和netty3 IO worker線程,嗯,兩個旅行團服務(wù)都不錯,效率很高。

          索性我把今天的見聞記錄下來,繪制成一張圖,當(dāng)然不重要的地方我就忽略了。

          2、操作系統(tǒng)發(fā)送數(shù)據(jù)包

          我在操作系統(tǒng)socket緩沖區(qū),經(jīng)過了很多神奇的事情。

          1. 在一個叫傳輸層的地方給我追加上了目標(biāo)端口號、源端口號

          2. 在一個叫網(wǎng)絡(luò)層的地方給我追加上了目標(biāo)IP、源IP,同時通過目標(biāo)IP與掩碼做與運算,找到“下一跳”的IP

          3. 在一個叫數(shù)據(jù)鏈路層的地方通過ARP協(xié)議給我追加上了“下一跳”的目標(biāo)MAC地址、源MAC地址

          最有意思的是,我們坐的都是一段一段纜車,每換一個纜車,就要修改目標(biāo)MAC地址、源MAC地址,后來問了同行的數(shù)據(jù)包小伙伴,這個模式叫“下一跳”,一跳一跳的跳過去。這里有很多數(shù)據(jù)包,體型大的單獨一個纜車,體型小的幾個擠一個纜車,還有一個可怕的事情,體型再大一點,要分拆做多個纜車(雖然這對我們數(shù)據(jù)包沒啥問題),這個叫拆包和粘包。期間我們經(jīng)過交換機、路由器,這些地方玩起來很Happy。

          當(dāng)然也有不愉快的事情,就是擁堵,目的地纜車滿了,來不及被拉走,只能等待咯。

          3、在Provider端的經(jīng)歷

          好不容易,我來到了目的地,我坐上了一個叫“零拷貝”號的快艇,迅速到了netty4,netty4果然富麗堂皇,經(jīng)過NioEventLoop#processSelectedKeys,再經(jīng)過pipeline中的各種入站handler,我來到了AllChannelHandler的線程池,當(dāng)然我有很多選擇,但是我隨便選了一個目的地,這里會經(jīng)歷解碼、一系列的Filter,才會來的目的地“業(yè)務(wù)方法”,NettyCodecAdapter#InternalDecoder解碼器很厲害,他可以處理拆包和粘包。

          在AllChannelHandler的線程池中我會停留一會,于是我也畫了一張圖,記錄旅程。

          自此,我的旅行結(jié)束,新的故事將由新的數(shù)據(jù)包續(xù)寫。

          4、Provider端產(chǎn)生了新的數(shù)據(jù)包

          我是一個數(shù)據(jù)包,出生在一個叫Dubbo2.7.3 Provider的小鎮(zhèn),我的使命是去喚醒命中注定的線程,接下來我會開始一段旅行,去一個叫Dubbo2.5.3 Consumer的地方。

          在Provider業(yè)務(wù)方法執(zhí)行之后

          • 由業(yè)務(wù)線程經(jīng)過io.netty.channel.AbstractChannelHandlerContext#writeAndFlush
          • 再經(jīng)過io.netty.util.concurrent.SingleThreadEventExecutor#execute 執(zhí)行addTask
          • 將任務(wù)放入隊列io.netty.util.concurrent.SingleThreadEventExecutor#taskQueue
          • 我便跟隨著io.netty.channel.AbstractChannelHandlerContext$WriteTask等待NioEventLoop發(fā)車,等待的過程中,我記錄了走過的腳步。

          在這里,我看到NioEventLoop是一個死循環(huán),不停地從任務(wù)隊列取任務(wù),執(zhí)行任務(wù)AbstractChannelHandlerContext.WriteAndFlushTask,然后指引我們到socket緩沖區(qū)等候,永不知疲倦,我似乎領(lǐng)略到他身上有一種倔強的、追求極致的匠人精神。

          經(jīng)過io.netty.channel.AbstractChannel.AbstractUnsafe#write,我到達了操作系統(tǒng)socket緩沖區(qū)。在操作系統(tǒng)層面和大多數(shù)數(shù)據(jù)包一樣,也是做纜車達到目的地。

          5、到達dubbo 2.5.3 Consumer端

          到達dubbo 2.5.3 Consumer端,我在操作系統(tǒng)socket緩沖區(qū)等了一會,同樣是坐了“零拷貝”號快艇,到達了真正的目的地dubbo 2.5.3 Consumer,在這里我發(fā)現(xiàn),NioWorker#run是一個死循環(huán),然后執(zhí)行NioWorker#processSelectedKeys,通過NioWorker#read方式讀出來,我就到達了AllChannelHandler的線程池,這是一個業(yè)務(wù)線程池。

          我在這里等待一會,等任務(wù)被調(diào)度,我看見com.alibaba.dubbo.remoting.exchange.support.DefaultFuture#doReceived被執(zhí)行了,同時Condition的signal被執(zhí)行了。我在遠(yuǎn)處看到了一個被阻塞線程被喚醒,我似乎明白,因為我的到來,喚醒了一個沉睡的線程,我想這應(yīng)該是我生命的意義。

          至此,我的使命也完成了,本次旅程結(jié)束。

          總結(jié)netty3和netty4的線程模型

          我們根據(jù)兩個數(shù)據(jù)包的自述,來總結(jié)一下netty3和netty4的線程模型。

          1、netty3寫過程

          2、Netty4的讀寫過程

          說明:這里沒有netty3的讀過程,netty3讀過程和netty4相同,pipeline是由IO線程執(zhí)行。

          總結(jié):netty3與netty4線程模型的區(qū)別在于寫過程,netty3中pipeline由業(yè)務(wù)線程執(zhí)行,而netty4無論讀寫,pipeline統(tǒng)一由IO線程執(zhí)行。

          netty4中ChannelPipeline中的Handler鏈統(tǒng)一由I/O線程串行調(diào)度,無論是讀還是寫操作,netty3中的write操作時由業(yè)務(wù)線程處理Handler鏈。netty4中可以降低線程之間的上下文切換帶來的時間消耗,但是netty3中業(yè)務(wù)線程可以并發(fā)執(zhí)行Handler鏈。如果有一些耗時的Handler操作會導(dǎo)致netty4的效率低下,但是可以考慮將這些耗時操作放在業(yè)務(wù)線程最先執(zhí)行,不放在Handler里處理。由于業(yè)務(wù)線程可以并發(fā)執(zhí)行,同樣也可以提高效率。

          一些疑難問題排查

          有遇到一些比較典型的疑難問題,例如當(dāng)Provider答應(yīng)的didi.log耗時正常,而Consumer端超時了,此時有如下排查方向,didi.log的Filter其實處于非常里層,往往不能反映真實的業(yè)務(wù)方法執(zhí)行情況。

          1. Provider除了業(yè)務(wù)方向執(zhí)行外,序列化也有可能是耗時的,所以可以用arthas監(jiān)控最外側(cè)方法org.apache.dubbo.remoting.transport.DecodeHandler#received,排除業(yè)務(wù)方法耗時高的問題

          2. Provider中數(shù)據(jù)包寫入是否耗時,監(jiān)控io.netty.channel.AbstractChannelHandlerContext#invokeWrite方法

          3. 通過netstat 也能查看當(dāng)前tcp socket的一些信息,比如Recv-Q, Send-Q,Recv-Q是已經(jīng)到了接受緩沖區(qū),但是還沒被應(yīng)用代碼讀走的數(shù)據(jù)。Send-Q是已經(jīng)到了發(fā)送緩沖區(qū),但是對方還沒有回復(fù)Ack的數(shù)據(jù)。這兩種數(shù)據(jù)正常一般不會堆積,如果堆積了,可能就有問題了。

          1. 看Consumer NioWorker#processSelectedKeys (dubbo2.5.3)方法是否耗時高。

          2. 直到最終整個鏈路的所有細(xì)節(jié)……問題肯定是可以解決的。

          尾聲

          在整個交互過程中,筆者省略線程棧調(diào)用的一些細(xì)節(jié)和源代碼的細(xì)節(jié),例如序列化與反序列化,dubbo怎么讀出完整的數(shù)據(jù)包的,業(yè)務(wù)方法執(zhí)行前那些Filter是怎么排序和分布的,netty的Reactor模式是如何實現(xiàn)的。這些都是非常有趣的問題……


          • 搜索關(guān)注微信公眾號"捉蟲大師",后端技術(shù)分享,架構(gòu)設(shè)計、性能優(yōu)化、源碼閱讀、問題排查、踩坑實踐。
          • 想進技術(shù)交流群的小伙伴加我微信「MrRoshi」備注加群即可,群里大佬如云,帶你起飛~
          - END -
          瀏覽 29
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <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>
                  国产成人无码在线高清播放 | 欧美色图1 | 曰韩人妻一区二区 | 成全在线观看高清的 | 欧美A片网站 |