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