使用 DeepFlow Wasm 插件实现业务可观测性

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 自定义过滤:对调用日志进行基于 URL、Endpoint 等字段的过滤

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

01-client_error_metrics

在 DeepFlow 调用日志页面,可以看到客户端异常的调用日志的详情信息,整个 JSON body 放在了 response_result 里面:

02-request_log

02-request_log

对该调用发起追踪,能看到是因为 fauths 返回的 401 异常:

03-tracing

03-tracing

下面是详细的调用链。第一步发起 DNS 请求:

04-dns

04-dns

第二步调用后端服务验证 License:

05-license

05-license

第三步发起 DNS 请求 fauths 服务的地址:

06-dns

06-dns

第四步调用 fauth 的 /auth API 验证权限,中间需要访问 Redis 获取用户信息:

07-fauth

07-fauth

08-redis

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

08-metrics

09-request-log

09-request-log

10-tracing

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

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 团队提供从代码到基础设施的监控及诊断

相关文章
|
6月前
|
数据采集 Cloud Native Java
在 GraalVM 静态编译下无侵入实现可观测探索
在 GraalVM 静态编译下无侵入实现可观测探索
112563 21
|
4月前
|
监控 Kubernetes Go
全链路追踪 & 性能监控,GO 应用可观测全面升级
当前,大多数面向 Golang 应用的监控能力主要是通过 SDK 方式接入,需要开放人员手动进行埋点,会存在一定问题。对此,可观测 Go Agent 应运而生。本文介绍的阿里云可观测 Go Agent 方案,能通过无侵入的方式实现应用监控能力。
108703 23
|
6月前
|
传感器 JavaScript 算法
Higress 全新 Wasm 运行时,性能大幅提升(二)
WAMR 是最早由 Intel 团队开发,在字节码联盟(Bytecode Alliance,面向 Wasm 软件生态的非盈利组织)下的一个广受欢迎的 WebAssembly 运行时开源项目。
124 2
|
3月前
|
Prometheus 监控 数据可视化
Grafana 插件生态系统:扩展你的监控能力
【8月更文第29天】Grafana 是一个流行的开源平台,用于创建和共享统计数据的仪表板和可视化。除了内置的支持,Grafana 还有一个强大的插件生态系统,允许用户通过安装插件来扩展其功能。本文将介绍一些 Grafana 社区提供的插件,并探讨它们如何增强仪表盘的功能性。
246 1
|
3月前
|
Prometheus 监控 Cloud Native
【揭秘可观测性】构建完美参考框架,打造系统监控的瑞士军刀!
【8月更文挑战第25天】在现代软件设计中,可观测性是确保系统稳定性和效率的关键因素。它主要由日志、指标及链路追踪(统称LMx)三大核心组件构成。本文详细介绍了构建高效可观测性框架的六个步骤:需求分析、工具选择、数据收集策略设计、实施集成、数据可视化及持续优化。并通过一个Spring Boot应用集成Prometheus和Micrometer收集指标的示例,展示了具体实践方法。合理构建可观测性框架能显著提升团队对软件系统的管理和监控能力,进而增强系统整体性能和可靠性。
76 2
|
4月前
|
运维 Prometheus Kubernetes
kubevela可观测体系问题之KubeVela 的可观测性能力通过插件机制进行扩展的问题如何解决
kubevela可观测体系问题之KubeVela 的可观测性能力通过插件机制进行扩展的问题如何解决
|
6月前
|
自然语言处理 Cloud Native 安全
适应多样化需求:WASM 插件在全链路灰度发布中的应用
MSE(微服务引擎)在微服务全链路灰度场景下提供了一套成熟的功能,支持内容规则和百分比规则的灰度路由策略。
61642 15
|
6月前
|
NoSQL Java Redis
Higress 全新 Wasm 运行时,性能大幅提升
在 Higress 将 Wasm 运行时从 V8 替换为 WAMR 后,Wasm 插件的性能对比之前又有了大幅提升。
46 2
|
6月前
|
微服务
构建可观测性参考框架
【2月更文挑战第13天】可观测性是一个快速发展的领域。
|
Prometheus 监控 Cloud Native
Go语言微服务框架 - 13.监控组件Prometheus的引入
今天我们专注于自定义服务中的Prometheus的监控,在框架中引入Prometheus相关的组件。关于更细致的使用方式,我会给出相关的链接,有兴趣进一步学习Prometheus的同学可以边参考资料边实践。
228 0