1
簡介
DeepFlow 利用 eBPF 采集并解析應(yīng)用協(xié)議,實(shí)現(xiàn)了零侵?jǐn)_的分布式追蹤和指標(biāo)數(shù)據(jù)的采集。DeepFlow 已經(jīng)內(nèi)置支持了十多種應(yīng)用協(xié)議的解析,并且還在持續(xù)增加中。但我們發(fā)現(xiàn)實(shí)際業(yè)務(wù)環(huán)境中情況會(huì)更加復(fù)雜:開發(fā)會(huì)堅(jiān)持返回 HTTP 200 同時(shí)將錯(cuò)誤信息放到自定義 JSON 結(jié)構(gòu)中,大量 RPC 的 Payload 部分使用 Protobuf、Thrift 等依賴 Schema 進(jìn)行解碼的序列化方式,調(diào)用的處理流程中發(fā)生了跨線程導(dǎo)致 eBPF AutoTracing 斷鏈。
針對(duì)這些復(fù)雜場景,DeepFlow 實(shí)現(xiàn)了一套零侵?jǐn)_的 WebAssembly 插件機(jī)制,使得開發(fā)人員可針對(duì)自己的業(yè)務(wù)環(huán)境定制化 DeepFlow 的協(xié)議解析能力。本文將分享兩個(gè)案例,來介紹 DeepFlow 中的 Wasm 插件能力。
02
案例 - 解析 JSON 中的錯(cuò)誤信息
在本例中,被監(jiān)控 HTTP API 的響應(yīng)消息為 JSON 格式,當(dāng) API 出錯(cuò)時(shí) HTTP 協(xié)議的狀態(tài)碼可能仍然是 200,確切的錯(cuò)誤信息通過 JSON 中的 OPT_STATUS 等字段返回
{ "OPT_STATUS":"AUTH_HEADER_ERROR",//不等于SUCCESS時(shí)表示調(diào)用失敗 "DESCRIPTION":"請(qǐng)傳遞正確的驗(yàn)證頭信息",//詳細(xì)錯(cuò)誤信息 ...//其他返回字段 }
查閱 API 文檔后我們得知,OPT_STATUS的值不等于SUCCESS時(shí)表示 API 調(diào)用失敗。在常規(guī)的 DeepFlow 解析流程中,會(huì)按照如下方式構(gòu)造 HTTP 調(diào)用日志的各個(gè)字段:
response_code:賦值為 HTTP 響應(yīng)頭中的狀態(tài)碼,例如 200、404、500 等
response_status:狀態(tài)碼小于 400 時(shí)認(rèn)為正常,4XX 認(rèn)為是客戶端異常,5XX 認(rèn)為是服務(wù)端異常
response_exception:賦值為 HTTP 異常狀態(tài)碼對(duì)應(yīng)的英文解釋,例如 404 時(shí)此字段賦值為 Not Found
response_result:當(dāng) HTTP 狀態(tài)碼為異常時(shí)賦值為整個(gè) HTTP Payload
當(dāng)我們安裝了 Wasm 插件后,我們可以在上述解析的基礎(chǔ)上,將失敗 API 的調(diào)用日志中的如下字段進(jìn)行覆寫,以實(shí)現(xiàn)正確體現(xiàn)業(yè)務(wù)錯(cuò)誤的效果:
response_code:當(dāng) JSON 中 OPT_STATUS != SUCCESS、且 HTTP 狀態(tài)碼小于 400 時(shí),此值覆寫為 500
response_status:按照新的 response_code 重新賦值,例如 500 時(shí)賦值為服務(wù)端異常
response_exception:當(dāng) JSON 中的 OPT_STATUS != SUCCESS時(shí)覆寫為 DESCRIPTION 字段的值
response_result:當(dāng) response_code 大于等于 400 時(shí)賦值為整個(gè) JSON Payload
我們將 Wasm 插件代碼放到了這個(gè) GitHub 倉庫[1]中。上述 API 行為描述的實(shí)際上是 DeepFlow 企業(yè)版中的 statistics 服務(wù),下面演示將此 Wasm 插件注入到 DeepFlow Agent 以后,對(duì) DeepFlow 企業(yè)版服務(wù)的自我觀測效果。首先我們?cè)诿钚兄杏|發(fā)一次 statistics 服務(wù)的 API 調(diào)用:
#請(qǐng)求 curlhttps://cloud.deepflow.yunshan.net/api/statistics/v1/stats/querier/DBDescription/ShowDatabases #HTTP響應(yīng)頭 HTTP/2401 date:Tue,22Aug20230129GMT content-type:application/json content-length:152 #HTTP響應(yīng)體 { "DATA":false, "DESCRIPTION":"請(qǐng)傳遞正確的驗(yàn)證頭信息", "ERR":null, "LEVEL":0, "OPT_STATUS":"AUTH_HEADER_ERROR" }
上述 API 響應(yīng)中,HTTP 的狀態(tài)碼為 401,OPT_STATUS=AUTH_HEADER_ERROR。我們能在 DeepFlow 頁面正確的看到客戶端異常指標(biāo):
01-client_error_metrics
在 DeepFlow 調(diào)用日志頁面,可以看到客戶端異常的調(diào)用日志的詳情信息,整個(gè) JSON body 放在了response_result里面:
02-request_log
對(duì)該調(diào)用發(fā)起追蹤,能看到是因?yàn)閒auths返回的 401 異常:
03-tracing
下面是詳細(xì)的調(diào)用鏈。第一步發(fā)起 DNS 請(qǐng)求:
04-dns
第二步調(diào)用后端服務(wù)驗(yàn)證 License:
05-license
第三步發(fā)起 DNS 請(qǐng)求 fauths 服務(wù)的地址:
06-dns
第四步調(diào)用 fauth 的 /auth API 驗(yàn)證權(quán)限,中間需要訪問 Redis 獲取用戶信息:
07-fauth
08-redis
03
案例 - 提取流水號(hào)并用于分布式追蹤
在金融行業(yè)的核心交易系統(tǒng)中,服務(wù)之間通常通過在 RPC 中傳遞一個(gè)流水號(hào)來實(shí)現(xiàn)分布式追蹤。本例中我們編寫了一個(gè)演示 Demo 服務(wù),它演示了一個(gè)簡單的 gRPC 客戶端和服務(wù)端。我們知道 gRPC 的消息體是使用 Protobuf 序列化的,本例將演示如何利用 DeepFlow 的 Wasm 插件機(jī)制解析這個(gè) Demo 中的 Protobuf 消息,獲取其中的流水號(hào),并最終實(shí)現(xiàn)分布式追蹤。Wasm 插件的代碼可以在這個(gè) GitHub 倉庫[2]中找到。
本例中的 gRPC 消息定義如下:
serviceGame{ rpcGame(OrderRequest)returns(OrderResponse); } messageOrderRequest{ stringbusiness_id=1235; } messageOrderResponse{ stringmsg=1235; }
在 Wasm 插件中,我們將 gRPC Payload 中的 business_id 字段的值賦值到 trace_id 中,用于分布式調(diào)用鏈追蹤。同時(shí)會(huì)將 business_id 及 msg 等原始字段在調(diào)用日志的 Native tag 中存儲(chǔ)一份,分別對(duì)應(yīng) attribute.business_id 及 attribute.msg,可用于業(yè)務(wù)查看更詳細(xì)的交易信息。
我們將 gRPC Demo 部署在 cloud.deepflow 環(huán)境中 Sandbox K8s 集群里,安裝好 Wasm 插件后,在 DeepFlow 頁面直接過濾 l7_protocol = Custom 即可看到這個(gè)私有協(xié)議的指標(biāo)和調(diào)用日志數(shù)據(jù):
08-metrics
09-request-log
10-tracing
04
如何使用 Golang SDK 開發(fā)插件
Wasm 插件可使用多種語言開發(fā),目前 DeepFlow 對(duì) Golang 提供了一個(gè) SDK,開發(fā)可以參考文檔[3]。其中核心的步驟如下:
新建一個(gè) go 項(xiàng)目, 并且拉取 Golang SDK
gomodinitProjectName&&gogetgithub.com/deepflowio/deepflow-wasm-go-sdk
在插件中實(shí)現(xiàn)協(xié)議解析邏輯
packagemain import( "github.com/deepflowio/deepflow-wasm-go-sdk/sdk" ) funcmain(){ sdk.Warn("pluginloaded") sdk.SetParser(SomeParser{}) } typeSomeParserstruct{ } func(pSomeParser)HookIn()[]sdk.HookBitmap{ return[]sdk.HookBitmap{ //一般只需要hook協(xié)議解析 sdk.HOOK_POINT_PAYLOAD_PARSE, } } func(pdnsParser)OnHttpReq(ctx*sdk.HttpReqCtx)sdk.HttpAction{ returnsdk.ActionNext() } func(pdnsParser)OnHttpResp(ctx*sdk.HttpRespCtx)sdk.HttpAction{ returnsdk.ActionNext() } func(pdnsParser)OnCheckPayload(ctx*sdk.ParseCtx)(uint8,string){ //這里是協(xié)議判斷的邏輯,返回0表示失敗 //return0,"" return1,"someprotocol" } func(pdnsParser)OnParsePayload(ctx*sdk.ParseCtx)sdk.ParseAction{ //這里是解析協(xié)議的邏輯 ifctx.L4!=sdk.TCP||ctx.L7!=1{ returnsdk.ActionNext() } returnsdk.ActionNext() }
編譯為 Wasm 插件
tinygobuild-owasm.wasm-targetwasi-panic=trap-scheduler=none-no-debug*.go
05
如何在 DeepFlow 中部署插件
將編譯好的插件上傳至 deepflow-server
deepflow-ctlplugincreate--typewasm--imagewasm.wasm--namewasm-demo-1
修改 deepflow-agent 的組配置,添加需要加載的插件
static_config: ebpf: #對(duì)于deepflow-agent原生不支持的協(xié)議,eBPF數(shù)據(jù)需要添加端口白名單才能上報(bào) kprobe-whitelist: port-list:9999 #如果配置了l7-protocol-enabled,別忘了放行Custom類型的協(xié)議 l7-protocol-enabled: -Custom #otherprotocol wasm-plugins: -wasm-demo-1//對(duì)應(yīng)deepflow-ctl上傳插件的名稱
注:目前修改此配置后 deepflow-agent 會(huì)自動(dòng)重啟。
檢查插件是否正確加載
kubectl-ndeepflowlogs-fdeepflow-agent-xxxxx|grep-iplugin
11-check
我們看到插件 main 函數(shù)里的 warn 日志正常輸出,說明插件加載成功了。
06
總結(jié)
DeepFlow Wasm 插件機(jī)制提供了一個(gè)可編程的、安全的、資源消耗可控的運(yùn)行沙箱,它是整個(gè) DeepFlow Pipeline 機(jī)制的重要一環(huán)。它的使用場景包括:
增強(qiáng)原生支持的協(xié)議:在原生協(xié)議的解析能力基礎(chǔ)之上,提取更多的業(yè)務(wù)信息
支持私有協(xié)議的解析:特別是從 Protobuf、Thrift 等依賴 Schema 的 Payload 內(nèi)容中提取業(yè)務(wù)字段
零侵?jǐn)_分布式追蹤:通過解析調(diào)用中的事務(wù)全局 ID,用于實(shí)現(xiàn)分布式追蹤
自定義脫敏:對(duì) MySQL、Redis 等協(xié)議中的業(yè)務(wù)敏感信息進(jìn)行抹除
未來,我們還會(huì)基于 Wasm 插件提供更強(qiáng)大的可編程性。例如:
自定義過濾:對(duì)調(diào)用日志進(jìn)行基于 URL、Endpoint 等字段的過濾
自定義采樣:通過對(duì) TraceID 等追蹤字段的分析,決定是否對(duì)調(diào)用日志進(jìn)行采樣丟棄
07
什么是 DeepFlow
DeepFlow[4] 開源項(xiàng)目旨在為復(fù)雜的云原生應(yīng)用提供深度可觀測性。DeepFlow 基于 eBPF 實(shí)現(xiàn)了零插樁(Zero Code)、全覆蓋(Full Stack)的指標(biāo)、追蹤、日志采集,并通過智能標(biāo)簽技術(shù)實(shí)現(xiàn)了所有觀測數(shù)據(jù)的全關(guān)聯(lián)(Universal Tagging)和高效存取。使用 DeepFlow,可以讓云原生應(yīng)用自動(dòng)具有深度可觀測性,從而消除開發(fā)者不斷插樁的沉重負(fù)擔(dān),并為 DevOps/SRE 團(tuán)隊(duì)提供從代碼到基礎(chǔ)設(shè)施的監(jiān)控及診斷能力。
編輯:黃飛
-
API
+關(guān)注
關(guān)注
2文章
1465瀏覽量
61682 -
HTTP
+關(guān)注
關(guān)注
0文章
496瀏覽量
30897 -
服務(wù)端
+關(guān)注
關(guān)注
0文章
66瀏覽量
6959 -
JSON
+關(guān)注
關(guān)注
0文章
114瀏覽量
6921
原文標(biāo)題:什么是 DeepFlow
文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論