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

我是一個(gè)Dubbo數(shù)據(jù)包,我的旅行開始了!

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

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

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

一些有趣的問題

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

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

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

有意思的旅行

1.Dubbo2.5.3 Consumer端發(fā)起請(qǐng)求

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

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

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

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

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

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

索性我把今天的見聞?dòng)涗浵聛?lái),繪制成一張圖,當(dāng)然不重要的地方我就忽略了。

圖片

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

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

  • 在一個(gè)叫傳輸層的地方給我追加上了目標(biāo)端口號(hào)、源端口號(hào)
  • 在一個(gè)叫網(wǎng)絡(luò)層的地方給我追加上了目標(biāo)IP、源IP,同時(shí)通過(guò)目標(biāo)IP與掩碼做與運(yùn)算,找到“下一跳”的IP
  • 在一個(gè)叫數(shù)據(jù)鏈路層的地方通過(guò)ARP協(xié)議給我追加上了“下一跳”的目標(biāo)MAC地址、源MAC地址

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

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

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

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

圖片

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

圖片

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

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

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

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

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

圖片

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

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

5.到達(dá)dubbo 2.5.3 Consumer端

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

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

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

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

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

1.netty3寫過(guò)程

圖片

2.Netty4的讀寫過(guò)程

圖片

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

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

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

一些疑難問題排查

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

  • Provider除了業(yè)務(wù)方向執(zhí)行外,序列化也有可能是耗時(shí)的,所以可以用arthas監(jiān)控最外側(cè)方法org.apache.dubbo.remoting.transport.DecodeHandler#received,排除業(yè)務(wù)方法耗時(shí)高的問題
  • Provider中數(shù)據(jù)包寫入是否耗時(shí),監(jiān)控io.netty.channel.AbstractChannelHandlerContext#invokeWrite方法
  • 通過(guò)netstat 也能查看當(dāng)前tcp socket的一些信息,比如Recv-Q, Send-Q,Recv-Q是已經(jīng)到了接受緩沖區(qū),但是還沒被應(yīng)用代碼讀走的數(shù)據(jù)。Send-Q是已經(jīng)到了發(fā)送緩沖區(qū),但是對(duì)方還沒有回復(fù)Ack的數(shù)據(jù)。這兩種數(shù)據(jù)正常一般不會(huì)堆積,如果堆積了,可能就有問題了。

圖片

  • 看Consumer NioWorker#processSelectedKeys (dubbo2.5.3)方法是否耗時(shí)高。
  • 直到最終整個(gè)鏈路的所有細(xì)節(jié)……問題肯定是可以解決的。

尾聲

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

責(zé)任編輯:武曉燕 來(lái)源: 捉蟲大師
相關(guān)推薦

2022-05-16 08:42:26

Pandasbug

2022-03-07 05:53:41

線程CPU代碼

2013-05-21 09:32:11

ChromebookChrome OS

2022-04-06 08:47:03

Dubbo服務(wù)協(xié)議

2021-12-29 19:20:41

數(shù)據(jù)GitHub服務(wù)器

2022-11-18 14:15:13

2020-11-04 07:56:19

工具Linux 翻譯

2024-10-25 12:38:27

2021-04-28 14:31:35

Dubbo接口日志

2012-11-28 13:25:27

程序員

2022-11-10 09:28:40

框架開發(fā)

2020-09-27 14:13:50

Spring BootJava框架

2021-09-13 08:41:52

職場(chǎng)互聯(lián)網(wǎng)自閉

2014-06-27 18:22:19

2019-12-23 11:03:07

抽象MOVJava

2022-12-26 09:15:13

2021-09-28 13:42:55

Chrome Devwebsocket網(wǎng)絡(luò)協(xié)議

2024-11-11 14:57:56

JWTSession微服務(wù)

2009-01-05 15:31:41

2019-08-28 13:03:16

戴爾
點(diǎn)贊
收藏

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