使用 DeepFlow Wasm 插件实现业务可观测性
1|简介
DeepFlow 利用 eBPF 采集并解析应用协议,实现了零侵扰的分布式追踪和指标数据的采集。DeepFlow 已经内置支持了十多种应用协议的解析,并且还在持续增加中。但我们发现实际业务环境中情况会更加复杂:开发会坚持返回 HTTP 200 同时将错误信息放到自定义 JSON 结构中,大量 RPC 的 Payload 部分使用 Protobuf、Thrift 等依赖 Schema 进行解码的序列化方式,调用的处理流程中发生了跨线程导致 eBPF AutoTracing 断链。
针对这些复杂场景,DeepFlow 实现了一套零侵扰的 WebAssembly 插件机制,使得开发人员可针对自己的业务环境定制化 DeepFlow 的协议解析能力。本文将分享两个案例,来介绍 DeepFlow 中的 Wasm 插件能力。
同时,欢迎大家报名参与 9月16日 DeepFlow开展的线下活动《可观测性 Meetup》!
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 仓库中。上述 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 页面正确的看到客户端异常指标(本例中插件注入在 cloud.deepflow K8s 集群的 deepflow-agent 中):
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 仓库中找到。
本例中的 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 即可看到这个私有协议的指标和调用日志数据:
08-metrics
09-request-log
10-tracing
04|如何使用 Golang SDK 开发插件
Wasm 插件可使用多种语言开发,目前 DeepFlow 对 Golang 提供了一个 SDK,开发可以参考文档。其中核心的步骤如下:
-
新建一个 go 项目, 并且拉取 Golang SDK
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() }
-
编译为 Wasm 插件
tinygo build -o wasm.wasm -target wasi -panic=trap -scheduler=none -no-debug *.go
05|如何在 DeepFlow 中部署插件
-
将编译好的插件上传至 deepflow-server
deepflow-ctl plugin create --type wasm --image wasm.wasm --name wasm-demo-1
-
修改 deepflow-agent 的组配置,添加需要加载的插件
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
11-check
我们看到插件 main 函数里的 warn 日志正常输出,说明插件加载成功了。
06|总结
DeepFlow Wasm 插件机制提供了一个可编程的、安全的、资源消耗可控的运行沙箱,它是整个 DeepFlow Pipeline 机制的重要一环。它的使用场景包括:
-
增强原生支持的协议:在原生协议的解析能力基础之上,提取更多的业务信息
-
支持私有协议的解析:特别是从 Protobuf、Thrift 等依赖 Schema 的 Payload 内容中提取业务字段
-
零侵扰分布式追踪:通过解析调用中的事务全局 ID,用于实现分布式追踪
-
自定义脱敏:对 MySQL、Redis 等协议中的业务敏感信息进行抹除
未来,我们还会基于 Wasm 插件提供更强大的可编程性。例如:
-
自定义过滤:对调用日志进行基于 URL、Endpoint 等字段的过滤
-
自定义采样:通过对 TraceID 等追踪字段的分析,决定是否对调用日志进行采样丢弃
07|什么是 DeepFlow
DeepFlow 开源项目旨在为复杂的云原生应用提供深度可观测性。DeepFlow 基于 eBPF 实现了零插桩(Zero Code)、全覆盖(Full Stack)的指标、追踪、日志采集,并通过智能标签技术实现了所有观测数据的全关联(Universal Tagging)和高效存取。使用 DeepFlow,可以让云原生应用自动具有深度可观测性,从而消除开发者不断插桩的沉重负担,并为 DevOps/SRE 团队提供从代码到基础设施的监控及诊断能力。
GitHub 地址:https://github.com/deepflowio/deepflow
访问 DeepFlow Demo,体验零插桩、全覆盖、全关联的可观测性。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
买彩票能中大奖?用Java盘点常见的概率悖论 | 京东云技术团队
引言 《双色球头奖概率与被雷劈中的概率哪个高?》 《3人轮流射击,枪法最差的反而更容易活下来?》 让我们用Java来探索ta们! 悖论1:著名的三门问题 规则描述:你正在参加一个游戏节目,你被要求在三扇门中选择一扇:其中一扇后面有一辆车;其余两扇后面则是山羊。你选择了一道门,假设是一号门,然后知道门后面有什么的主持人,开启了另一扇后面有山羊的门,假设是三号门。他然后问你:“你想选择二号门吗?请问若想获得车,参赛者应该换二号门吗? 论证:分析需求,拆解为如下代码 /** * <p> 三门问题解决方案 </p> * @author yuanfeng.wang * @since 2023/8/29 */ import java.util.Random; public class ThreeDoorSolution { public static void main(String[] args) { // 模拟执行1万次,打印获胜的概率 threeDoor(10000); } /** * 三门问题逻辑拆解 * @param nu...
- 下一篇
一款释放数据价值的项目,开源了!
在大数据和 AI 的时代背景下,数据已经成为了重要财富,大到政务数据、企业核心数据,小到个人信息、银行卡余额,这些数据无一例外都是“隐私数据”,如果在使用和流转时发生泄漏都会造成巨大的损失。 那有没有什么方法,可以在不暴露数据隐私的前提下,让数据流动起来发挥更大的价值呢?在这个问题的驱使下我们找到了今天的主角——隐私计算。 一、什么是隐私计算? 隐私计算是指在不泄露数据本身的情况下,实现数据分析和计算的技术,具有“数据可用不可见”的特点,让数据安全合规地流动起来。 下面用一个经典的百万富翁问题,来帮助理解什么是“数据可用不见”。 假设有两个百万富翁,他们都想知道谁更富有,但又不想让对方或者第三方,知道自己具体有多少钱。 数据本身:具体的财富值(数据) 计算:比大小(可用) 不泄露:对方或第三方(不可见) 按照常理,进行比大小的计算是需要知道两个数是多少,才能比较大小,但这里不知道具体的数字。所以上面这个问题在普通人看来是无解的,但其实这是一个密码学问题,也被称为“多方安全计算”(MPC)问题,由姚期智院士在 1982 提出,并给出了解决方案——混淆电路,实现了数据的可用不可见。 从隐私...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- MySQL8.0.19开启GTID主从同步CentOS8
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- CentOS6,7,8上安装Nginx,支持https2.0的开启