原創(chuàng)文章,歡迎轉(zhuǎn)載。轉(zhuǎn)載請(qǐng)注明:轉(zhuǎn)載自IT人故事會(huì),謝謝!
原文鏈接地址:『互聯(lián)網(wǎng)架構(gòu)』dubbo 調(diào)用埋點(diǎn)(114)
上邊幾次都是說的單體的攔截埋點(diǎn),應(yīng)用的內(nèi)部進(jìn)行的,很多的情況系統(tǒng)都是分布式的,怎么去監(jiān)聽RPC(遠(yuǎn)程過程調(diào)用),dubbo,RMI,springcloud,http。只要遠(yuǎn)程調(diào)用,跨進(jìn)程調(diào)用都屬于RPC,也不可能所有的能都涉及到,很多公司都有自己的封裝,例如阿里的HFS,這次只針對(duì)dubbo這種RPC進(jìn)行調(diào)用。
源碼:https://github.com/limingios/netFuture/tree/master/源碼/『互聯(lián)網(wǎng)架構(gòu)』調(diào)?鏈系統(tǒng)工程結(jié)構(gòu)(111)

(一)Dubbo執(zhí)行過程
對(duì)于dubbo的埋點(diǎn),首先要了解dubbo的執(zhí)行過程

| 節(jié)點(diǎn) | 角色說明 |
|---|---|
| Provider | 暴露服務(wù)的服務(wù)提供方 |
| Consumer | 調(diào)用遠(yuǎn)程服務(wù)的服務(wù)消費(fèi)方 |
| Registry | 服務(wù)注冊(cè)與發(fā)現(xiàn)的注冊(cè)中心 |
| Monitor | 統(tǒng)計(jì)服務(wù)的調(diào)用次數(shù)和調(diào)用時(shí)間的監(jiān)控中心 |
| Container | 服務(wù)運(yùn)行容器 |
-
Dubbo調(diào)用過程
-
消費(fèi)者調(diào)用過程
(二)調(diào)用端埋點(diǎn)實(shí)現(xiàn)
埋點(diǎn)目的
1.捕捉消費(fèi)者調(diào)用信息(遠(yuǎn)程接口、URL、參數(shù)、用時(shí)、返回結(jié)果、異常)
2.傳遞TraceRequest調(diào)用信息模型表結(jié)構(gòu)
| 名稱 | 類型 | 描述 |
|---|---|---|
| servicePath | string | 服務(wù)路徑 |
| serviceName | string | 服務(wù) |
| inParam | json | 返回結(jié)果 |
| outParam | json | 返回結(jié)果 |
| ErrorMessage | string | 異常信息 |
| ErrorStack | text | 異常堆棧 |
| ResultState | string | 執(zhí)行狀態(tài) |
| beginTime | date | 開始時(shí)間 |
| endTime | date | 結(jié)束時(shí)間 |
| addressIp | string | 遠(yuǎn)程IP |
| fromIp | string | 調(diào)用者IP |
- 埋點(diǎn)位置
如何才能完整的捕捉到以上信息呢?那么就需要了解Dubbo內(nèi)部的調(diào)用
1.分解調(diào)用過程為多個(gè)步驟。
2.這些步驟分別是在哪些協(xié)作線程上完成的?
3.經(jīng)過了哪些方法?
4.經(jīng)過了哪些過濾器?
-
調(diào)用過程分解&線程協(xié)作
- 選擇斷點(diǎn)位置Debug調(diào)試調(diào)用過程
-
消費(fèi)者調(diào)用線程源碼分析:
- 經(jīng)過對(duì)源碼的分析,埋點(diǎn)的位置如下:
DubboInvoker.doInvoke()
FutureFilter.invoke()
DubboInvoker.doInvoke() 方法最靠近調(diào)用方,異常捕捉范圍較大,但是該位置無法通過Attachment 向下傳遞TraceRequest 參數(shù),所以需要FutureFilter.invoke() 進(jìn)行補(bǔ)充,其具體分工如下:
·1.DubboInvoker.doInvoke捕獲如下信息: 1、開始時(shí)間 2、服務(wù)路徑 3、服務(wù)方法 4、輸入?yún)?shù) 5、異常信息 6、本地地址
2.FutureFilter.invoke 基于Attachment 向下傳遞參數(shù) 2、異常信息與堆棧 3、返回結(jié)果
DubboInvoker.doInvoke攔截源碼參見 :com.cbt.agent.collects.dubbo.DubboConsumerRpcExceptionMonitorHandle#invokerBefore
FutureFilter.invoke攔截源碼參見 :
com.cbt.agent.collects.dubbo.DubboConsumerMonitorHandle#invokerBefore
(三)調(diào)用端埋點(diǎn)實(shí)現(xiàn)
- 埋點(diǎn)目的
接收TraceRequest信息 ,并創(chuàng)建會(huì)話

- 埋點(diǎn)位置:
相對(duì)調(diào)用廣方接收方埋點(diǎn)目的較簡(jiǎn)單,但同樣需分析源碼找準(zhǔn)埋點(diǎn)位置
-
提供者處理線程分析
經(jīng)分析埋點(diǎn)位置選在離實(shí)際調(diào)用方法較遠(yuǎn)的EchoFilter過濾器理由是捕捉的信息更全面。
具體會(huì)話開啟過程:
- 基于Attachment獲取TraceId、ParentId、TraceProperties。
- 封裝TraceRequest ,并此為參數(shù)開啟會(huì)話。
- 在調(diào)用結(jié)束時(shí)關(guān)閉會(huì)話。
具體源碼參見:com.cbt.agent.collects.dubbo.DubboProviderMonitorHandle#invokerBefore

(二)Servlet處理埋點(diǎn)
Servlet埋點(diǎn)目的
1.生成TraceId
2.開啟關(guān)閉監(jiān)控會(huì)話
3.捕捉Http請(qǐng)求(url、客戶端IP、參數(shù)、響應(yīng)時(shí)長(zhǎng)、響應(yīng)狀態(tài)碼)埋點(diǎn)埋在哪?
1.每一個(gè)Control方法
2.DispatcherServlet.doDispatch方法
3.HttpServlet.service 方法方案對(duì)比
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| 應(yīng)用層Control類 | 簡(jiǎn)單,風(fēng)險(xiǎn)因素低 | 判別成本高,有局限性,只能根據(jù) HttpServlet 子類或@RequestMapping進(jìn)行識(shí)別。 |
| DispatcherServlet.doDispatch | 簡(jiǎn)單,適應(yīng)性強(qiáng) | 1、只能針對(duì)spring mvc 項(xiàng)目 2、spring boot 項(xiàng)目不支持 |
| HttpServlet.service | 適應(yīng)性強(qiáng),與應(yīng)用層和框架無關(guān) | 1、不同的容器ClassPath不一樣,存在兼容性問題。 2、存在風(fēng)險(xiǎn),幾乎所有請(qǐng)求都會(huì)經(jīng)過此方法 3、業(yè)務(wù)異常無法捕獲 |
總合比較還是選擇 HttpServlet.service 會(huì)更好些。
HttpServlet.service 埋點(diǎn)需要做的工作:
1.字節(jié)碼插樁
2.請(qǐng)求攔截并獲取請(qǐng)求信息字節(jié)碼插樁流程
字節(jié)碼插是指在數(shù)據(jù)裝載前在HttpServlet.service 插入監(jiān)控指令,以攔截Http請(qǐng)求,其插樁的過程。

請(qǐng)求攔截是指具體Http請(qǐng)求過來時(shí)進(jìn)行攔截過濾,這么做主要是為了完成兩個(gè)目的
1.開啟監(jiān)控會(huì)話
2.開啟對(duì)Servlet響應(yīng)過程的監(jiān)控


(三)Redis 調(diào)用埋點(diǎn)

- 埋點(diǎn)可選方案
| 方案 | 優(yōu)點(diǎn) | 缺點(diǎn) |
|---|---|---|
| 埋點(diǎn)jedis 類Get、Set等API方法 | 簡(jiǎn)單直接 | 工作量大,方法較多、需要了解每個(gè)方法特性 |
| 埋點(diǎn) Connection sendCommand方法 | 全面、所有命令都會(huì)經(jīng)過此方法 | 存在未知風(fēng)險(xiǎn)、不方便計(jì)算執(zhí)行時(shí)間、和返回結(jié)果 |
| 埋點(diǎn) Protocol | 全面、所有命令都會(huì)經(jīng)過此方法 | 存在未知風(fēng)險(xiǎn)、不方便計(jì)算執(zhí)行時(shí)間、和返回結(jié)果 |

PS:源碼中可以查看DevelopBootMain類,我看這代碼也看了2天,原來老寫業(yè)務(wù)代碼,看看這確實(shí)很容易懵X,確實(shí)這才是有技術(shù)含量的代碼。其實(shí)有沒有技術(shù)含量不太重要,重要是的有沒有商業(yè)價(jià)值。




