使用调试会话捕获请求链路
指标可以告诉你错误率上升了,访问日志可以告诉你请求匹配了哪个路由和上游,但两者都无法说明网关对失败请求实际执行了哪些操作。
调试会话可以回答这个问题。你可以选择实例、时间窗口和关注的流量。对于每个匹配的请求,网关会记录所有已执行的插件、执行顺序、各插件耗时以及产生的每一行日志。
可以排查哪些问题
哪个插件导致请求变慢。 某个结算端点耗时 400 ms,但你无法判断时间花在了哪里。链路会先按阶段、再按各个插件调用拆分请求,并显示每个调用的耗时,因此可以快速定位慢插件。
插件为什么没有生效。 插件执行顺序根据优先级计算,并合并路由、服务和全局规则上的配置。仅通过阅读配置推导执行顺序容易出错。链路会显示真实请求中实际执行的插件及网关的执行顺序,无需自行推导。
网关为某个特定请求记录了哪些日志。 该请求产生的日志行会附加到其链路中。你无需再提高生产环境的日志级别,也无需从大量输出中筛选属于同一请求的日志。
告警触发时发生了什么。 告警策略可以自动启动会话,在触发告警的流量发生时立即捕获,而不必在事后尝试复现间歇性故障。
工作原理
你可以针对某个网关组创建会话。控制面会将会话下发到所选实例,租约时长等于会话持续时间,因此时间窗口结束时会自动停止捕获。
每个匹配的请求都会记录为 OpenTelemetry 链路。数据面通过现有的心跳认证通道将数据发送到控制面。控制面把数据存储在你自己的 Jaeger 部署中,因此链路数据不会离开你的网络。
调试会话仅追踪 HTTP 流量,不追踪 Stream(L4)代理和 TLS 握手。
前置条件
- 一个至少包含一个在线实例的网关组,实例运行 API7 网关 3.9.13 或更高版本。
- 控制面已配置 Jaeger。Helm Chart 和 Docker Compose 部署默认包含 Jaeger。对于 RPM 安装,请自行部署 Jaeger,并在控制台和 DP Manager 配置中设置
jaeger.addr和jaeger.collector_addr。 - 具有网关组的
gateway:CreateDebugSession权限。
无需启用 opentelemetry 插件或静态 apisix.tracing 选项。调试会话使用独立的运行时开关。
步骤 1:启动会话
- 控制台
- API
-
前往 Gateway Groups,选择网关组,然后单击 Debug Sessions。
-
单击 Create Debug Session。
-
填写表单:
字段 说明 Name 会话标识符,最多 100 个字符。 Description 可选,用于说明启动会话的原因。 Target Instances 要追踪的实例,至少需要选择一个。 Duration (seconds) 实例保持追踪的时长,范围为 10 到 600 秒,默认值为 60。 Max Samples 会话列出 的链路数量,范围为 1 到 200,默认值为 5。 Sampling Rule 要捕获的请求。留空将捕获所有请求。 -
单击 Submit。会话页面会显示剩余捕获时间的倒计时,链路到达后将出现在列表中。
curl "https://localhost:7443/api/gateway_groups/${GATEWAY_GROUP_ID}/debug_sessions" -X POST \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "checkout-5xx",
"target_instances": ["'"${INSTANCE_ID}"'"],
"duration_secs": 300,
"max_samples": 50,
"sampling_rule": [["status", ">=", 500]]
}'
步骤 2:仅捕获关注的流量
在繁忙的网关上,捕获所有流量会淹没你正在查找的请求。采样规则可以把捕获范围缩小到相关流量。
规则在响应完成后求值,因此不仅可以按传入请求筛选,还可以按状态码、上游延迟等处理结果筛选。
仅筛选服务器错误:
[["status", ">=", 500]]
筛选某个端点的慢请求:
[["uri", "==", "/checkout"], ["upstream_response_time", ">", 1]]
筛选一个租户,匹配地址范围或请求头:
["OR", ["remote_addr", "ipmatch", "10.1.0.0/16"], ["http_x_tenant_id", "==", "acme"]]
规则由 [variable, operator, value] 条件组成。除非第一个元素是 OR、AND、!OR 或 !AND,否则条件默认以 AND 组合。
| 常用变量 | 说明 |
|---|---|
uri、request_uri、method、status | 路径、包含查询字符串的路径、方法和响应状态 |
host、remote_addr | 请求主机和客户端地址 |
route_id、route_name、service_id、service_name | 匹配的资源 |
consumer_name、consumer_group_id | 已通过身份认证的消费者 |
upstream_status、upstream_response_time | 上游结果和耗时 |
http_<header>、arg_<name>、cookie_<name> | 请求头、查询参数或 Cookie |
支持的运算符包括 ==、~=、>、>=、<、<=、用于正则表达式的 ~~ 和 ~*,以及 in、has 和 ipmatch。
uri、method 和 status 分别表示请求路径、方法和响应状态。不要写成 http_uri、http_method 或 http_status,因为 http_ 前缀表示读取同名请求头,这些表达式永远不会匹配,且会导致会话不提示错误便无法捕获任何内容。
控制台的 Match URI、Match Method 和 5xx Errors 预设按钮目前会插入带 http_ 前缀的形式。单击预设后,请编辑变量名。
步骤 3:读取链路
打开链路,以瀑布图形式查看请求。自上而下读取即可直接看到执行顺序:
GET /checkout 412ms
├─ apisix.phase.access 380ms
│ ├─ http_router_match 0.16ms
│ ├─ apisix.phase.rewrite.plugins.key-auth 3.1ms
│ ├─ apisix.phase.rewrite.plugins.proxy-rewrite 0.4ms
│ └─ apisix.phase.access.plugins.limit-count 371ms ←
├─ apisix.phase.header_filter 0.25ms
└─ apisix.phase.body_filter 1.4ms
每次插件调用都是一个独立的 Span,名称为 apisix.phase.<phase>.plugins.<plugin>,并嵌套在调用插件时处于打开状态的阶段 Span 下。同一阶段内,插件按优先级降序执行,链路也按此顺序显示。在本例中,limit-count 几乎占用了整个请求的耗时。
网关会为 access、header_filter 和 body_filter 打开阶段 Span。因此,包括 rewrite 阶段插件在内的请求侧插件都会显示在 apisix.phase.access 下。你还会看到用于路由匹配的 http_router_match、用于全局规则的 run_global_rules.<phase>,以及执行时出现的 resolve_dns 或 fetch_secret。
请求自身的日志
选择根 Span 并打开 Events 选项卡,可以查看该请求产生的日志行,包括日志级别、源位置和消息。
捕获过程不受网关所配置 error_log 级别的影响。因此,即使某条 debug 级消息从未写入错误日志,也会显示在这里。每个请求最多保留 200 条日志,每条最多 2048 字节。nginx 自身写入的日志行(例如上游连接错误)不会被捕获;以 Lua 表形式记录的结构化参数会显示为 {...}。
将日志作为 Span 事件捕获需要 API7 网关 3.9.15、3.10.2 或更高版本。
导出链路
单击 Download OTLP JSON,可以将链路导出为 OpenTelemetry 文档,便于附加到支持工单或离线分析。
告警触发时自动捕获
间歇性故障很难手动捕获:当有人看到告警并启动会话时,触发告警的请求通常早已结束。你可以改为让告警自动启动会话。
- 前往 Alerts,打开告警策略,然后找到 Debug Sessions 部分。
- 添加配置,设置持续时间、最大样本数和可选的采样规则。
策略触发时,控制面会针对满足条件的每个网关组,为每项配置创建一个会话,并以组中的所有实例为目标。告警历史记录会保存该会话,你可以直接从告警详情打开。
如果同一策略在该网关组上创建的会话仍处于活动状态,则不会创建新会话。因此,反复触发和恢复的告警只会产生一个捕获窗口,不会创建数百个会话;活动会话的持续时间相当于冷却时间。
在生产环境运行会话前
链路记录的是真实流量,请先了解其中会保存哪些内容。
会捕获:包含查询字符串的完整请求 URL;请求主机、方法和响应状态;User-Agent 请求头;路由、服务和实例标识符;插件和阶段名称及其耗时;请求自身的日志行。
不会捕获:请求体、响应体,以及 Host 和 User-Agent 以外的任何请求头或响应头。
链路内容按原样存储,不会脱敏。如果 URL 的查询字符串包含敏感值,或插件记录了敏感值,这些数据会出现在链路和导出 文件中。请优先使用精确的采样规则,而不是捕获所有流量,并限制 gateway:GetDebugSession 和 gateway:ExportDebugSession 权限。
限制和行为
| 属性 | 值 |
|---|---|
| 会话持续时间 | 10 到 600 秒 |
| 最大样本数 | 1 到 200。仅限制会话列出的链路数量,不限制实际捕获数量。在整个持续时间内,所有匹配规则的请求都会被捕获。 |
| 流量范围 | 仅 HTTP |
| 并发会话 | 不限制 |
| 链路保留时间 | 由 Jaeger 部署的保留策略决定 |
每个请求最多由一个会话捕获。有采样规则的会话优先于没有采样规则的会话;其他条件相同时,选择结果不确定。如果多人同时调试同一个网关组,请为每个会话设置采样规则。
停止会话会保留已经收集的链路。删除会话会从控制面移除会话及其链路列表,但 Span 数据会一直保留在 Jaeger 中,直到保留策略到期。若要删除捕获内容,请使用 Jaeger 部署自身的控制功能。