DeepFlow 利用 eBPF 采集并解析应用协议,实现了零侵扰的分布式追踪和指标数据的采集。DeepFlow 已经内置支持了十多种应用协议的解析,并且还在持续增加中。但我们发现实际业务环境中情况会更加复杂:开发会坚持返回 HTTP 200 同时将错误信息放到自定义 JSON 结构中,大量 RPC 的 Payload 部分使用 Protobuf、Thrift 等依赖 Schema 进行解码的序列化方式,调用的处理流程中发生了跨线程导致 eBPF AutoTracing 断链。
针对这些复杂场景,DeepFlow 实现了一套零侵扰的 WebAssembly 插件机制,使得开发人员可针对自己的业务环境定制化 DeepFlow 的协议解析能力。本文将分享两个案例,来介绍 DeepFlow 中的 Wasm 插件能力。
在本例中,被监控 HTTP API 的响应消息为 JSON 格式,当 API 出错时 HTTP 协议的状态码可能仍然是 200,确切的错误信息通过 JSON 中的 OPT_STATUS 等字段返回:
{
"OPT_STATUS": "AUTH_HEADER_ERROR", // 不等于 SUCCESS 时表示调用失败
"DESCRIPTION": "请传递正确的验证头信息", // 详细错误信息
... // 其他返回字段
}
查阅 API 文档后我们得知,OPT_STATUS的值不等于SUCCESS时表示 API 调用失败。在常规的 DeepFlow 解析流程中,会按照如下方式构造 HTTP 调用日志的各个字段:
当我们安装了 Wasm 插件后,我们可以在上述解析的基础上,将失败 API 的调用日志中的如下字段进行覆写,以实现正确体现业务错误的效果:
我们将 Wasm 插件代码放到了这个 GitHub 仓库[1]中。上述 API 行为描述的实际上是 DeepFlow 企业版中的 statistics 服务,下面演示将此 Wasm 插件注入到 DeepFlow Agent 以后,对 DeepFlow 企业版服务的自我观测效果。首先我们在命令行中触发一次 statistics 服务的 API 调用:
# 请求
curl https://cloud.deepflow.yunshan.net/api/statistics/v1/stats/querier/DBDescription/ShowDatabases
# HTTP 响应头
HTTP/2 401
date: Tue, 22 Aug 2023 01:44:29 GMT
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 页面正确的看到客户端异常指标:
在 DeepFlow 调用日志页面,可以看到客户端异常的调用日志的详情信息,整个 JSON body 放在了response_result里面:
对该调用发起追踪,能看到是因为fauths返回的 401 异常:
下面是详细的调用链。第一步发起 DNS 请求:
第二步调用后端服务验证 License:
第三步发起 DNS 请求 fauths 服务的地址:
第四步调用 fauth 的 /auth API 验证权限,中间需要访问 Redis 获取用户信息:
在金融行业的核心交易系统中,服务之间通常通过在 RPC 中传递一个流水号来实现分布式追踪。本例中我们编写了一个演示 Demo 服务,它演示了一个简单的 gRPC 客户端和服务端。我们知道 gRPC 的消息体是使用 Protobuf 序列化的,本例将演示如何利用 DeepFlow 的 Wasm 插件机制解析这个 Demo 中的 Protobuf 消息,获取其中的流水号,并最终实现分布式追踪。Wasm 插件的代码可以在这个 GitHub 仓库[2]中找到。
本例中的 gRPC 消息定义如下:
service Game{
rpc Game(OrderRequest) returns (OrderResponse);
}
message OrderRequest{
string business_id = 1235;
}
message OrderResponse{
string msg = 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 即可看到这个私有协议的指标和调用日志数据:
Wasm 插件可使用多种语言开发,目前 DeepFlow 对 Golang 提供了一个 SDK,开发可以参考文档[3]。其中核心的步骤如下:
go mod init ProjectName && go get github.com/deepflowio/deepflow-wasm-go-sdk
package main
import (
"github.com/deepflowio/deepflow-wasm-go-sdk/sdk"
)
func main(){
sdk.Warn("plugin loaded")
sdk.SetParser(SomeParser{})
}
type SomeParser struct {
}
func (p SomeParser) HookIn() []sdk.HookBitmap {
return []sdk.HookBitmap{
// 一般只需要 hook 协议解析
sdk.HOOK_POINT_PAYLOAD_PARSE,
}
}
func (p dnsParser) OnHttpReq(ctx *sdk.HttpReqCtx) sdk.HttpAction {
return sdk.ActionNext()
}
func (p dnsParser) OnHttpResp(ctx *sdk.HttpRespCtx) sdk.HttpAction {
return sdk.ActionNext()
}
func (p dnsParser) OnCheckPayload(ctx *sdk.ParseCtx) (uint8, string) {
// 这里是协议判断的逻辑, 返回 0 表示失败
// return 0, ""
return 1, "some protocol"
}
func (p dnsParser) OnParsePayload(ctx *sdk.ParseCtx) sdk.ParseAction {
// 这里是解析协议的逻辑
if ctx.L4 != sdk.TCP|| ctx.L7 != 1{
return sdk.ActionNext()
}
return sdk.ActionNext()
}
tinygo build -o wasm.wasm -target wasi -panic=trap -scheduler=none -no-debug *.go
deepflow-ctl plugin create --type wasm --image wasm.wasm --name wasm-demo-1
static_config:
ebpf:
# 对于 deepflow-agent 原生不支持的协议, eBPF 数据需要添加端口白名单才能上报
kprobe-whitelist:
port-list: 9999
# 如果配置了 l7-protocol-enabled,别忘了放行 Custom 类型的协议
l7-protocol-enabled:
- Custom
# other protocol
wasm-plugins:
- wasm-demo-1 // 对应 deepflow-ctl 上传插件的名称
注:目前修改此配置后 deepflow-agent 会自动重启。
kubectl -n deepflow logs -f deepflow-agent-xxxxx | grep -i plugin
我们看到插件 main 函数里的 warn 日志正常输出,说明插件加载成功了。
DeepFlow Wasm 插件机制提供了一个可编程的、安全的、资源消耗可控的运行沙箱,它是整个 DeepFlow Pipeline 机制的重要一环。它的使用场景包括:
未来,我们还会基于 Wasm 插件提供更强大的可编程性。例如:
DeepFlow[4] 开源项目旨在为复杂的云原生应用提供深度可观测性。DeepFlow 基于 eBPF 实现了零插桩(Zero Code)、全覆盖(Full Stack)的指标、追踪、日志采集,并通过智能标签技术实现了所有观测数据的全关联(Universal Tagging)和高效存取。使用 DeepFlow,可以让云原生应用自动具有深度可观测性,从而消除开发者不断插桩的沉重负担,并为 DevOps/SRE 团队提供从代码到基础设施的监控及诊断能力。
GitHub 地址:https://github.com/deepflowio/deepflow
访问 DeepFlow Demo[5],体验零插桩、全覆盖、全关联的可观测性。
这个 GitHub 仓库: https://github.com/deepflowio/deepflow-wasm-go-sdk/tree/main/example/http_status_rewrite
[2]这个 GitHub 仓库: https://github.com/deepflowio/deepflow-wasm-go-sdk/tree/main/example/go_http2_uprobe
[3]参考文档: https://deepflow.io/docs/zh/agent-integration/plguin/wasm/
[4]DeepFlow: https://github.com/deepflowio/deepflow
[5]DeepFlow Demo: https://deepflow.io/docs/zh/install/overview/