跳到主要内容
版本:3.10.x

诊断 CPU 和内存使用情况

当网关工作进程的 CPU 占用过高或内存持续增长时,可以使用 Diagnostic Agents。控制台会生成代理的部署命令和凭据,列出已连接的代理,并提供用于采集和下载诊断报告的终端。

代理运行在网关所在的宿主机上,通过 mTLS 连接到 DP Manager。控制台通过该连接转发诊断请求,因此代理无需发布端口或接受入站连接。每个代理都能看到其所在宿主机上的进程,包括所选网关组之外的进程。

备注

Diagnostic Agents 在 API7 Enterprise 3.10.7 中引入。请将控制台和 DP Manager 都升级到支持此功能的版本。ngxdig 镜像独立发布,可用的采集选项取决于已安装的镜像。本指南使用支持 cpu-on 和 memsnap 命令的终端。

如需查看单个请求的追踪和插件执行耗时,请参阅调试会话。

前置条件​

  • 已运行并获得许可证的 API7 网关部署,以及正在运行的网关实例。参阅使用 Docker Compose 部署或在 Kubernetes 上部署 API7 企业版。按照这些指南操作时,请为控制面选择 3.10.7 或更高版本的镜像标签;较早的示例标签不包含 Diagnostic Agents。
  • 管理员账号,或拥有 gateway:ListDiagnosticAgents、gateway:GetDiagnosticAgent、gateway:DeployDiagnosticAgent 和 gateway:UseDiagnosticAgentConsole 权限的角色。
  • 能够在网关宿主机上运行 Docker 命令,或在网关所在节点上创建生成的 Kubernetes Secret 和 Pod。
  • ngxdig 镜像支持的 Linux 宿主机。CPU 性能分析要求内核版本至少为 5.10、/sys/kernel/btf 下存在内核 BTF 数据,并具有使用 eBPF 和性能事件的权限。以下流程已在 Linux amd64 上验证。
  • 代理可访问的 DP Manager TLS 地址,通常使用 7943 端口。请使用部署中配置的地址,并确保主机名包含在证书中。控制台的浏览器访问地址不一定是 DP Manager 地址。
  • 在高可用部署中,每个 DP Manager 都必须能够通过其他 DP Manager 公布的地址访问它们。除非对等实例能够访问从已接受连接推导出的容器地址,否则请配置 server.advertise。参阅控制面高可用。

内存快照读取进程内存和 /proc,不需要 eBPF,但仍需能够访问目标进程及其 PID 命名空间。

警告

生成的部署会共享宿主机的 PID 命名空间,并授予包括 BPF、PERFMON、SYS_PTRACE 和 SYS_ADMIN 在内的 Linux capabilities(权能)。仅在需要诊断的宿主机上部署。生成的命令或清单包含私钥;请妥善保管,不要将其附加到支持工单中。

部署诊断代理​

在控制台中打开 Diagnostic Agents,选择 Add Diagnostic Agent,然后选择与网关宿主机匹配的部署方式。

Docker​

  1. 选择 Docker。

  2. 将 Control Plane Address 设置为代理容器能够访问的 DP Manager TLS URL,包含 https:// 协议和端口。

  3. 将 Name 设置为便于识别宿主机的名称。将下文所有 Docker 命令中的 <agent-container> 替换为此名称。可以按需将 Image 设置为已批准的 ngxdig 镜像,并选择 Certificate Validity Period。

  4. 选择 Generate,将完整命令保存到私有文件中,例如 diagnostic-agent.sh。

  5. 在网关所在的同一 Docker 宿主机上运行生成的命令:

    chmod 700 diagnostic-agent.sh
    bash diagnostic-agent.sh

命令包含 --pid host、Linux capabilities 和 mTLS 凭据。请保留这些设置。该命令不会发布代理端口。

如果 DP Manager 地址使用 Docker Compose 服务名,请在生成的 docker run 选项中、镜像名称之前添加 --network <control-plane-network>。例如,使用 https://dp-manager:7943 的代理必须加入能够解析 dp-manager 的网络。代理容器内的 localhost 指的是该容器,而不是 Docker 宿主机。

检查代理日志:

docker logs <agent-container> --tail=50

连接成功时会报告 session established。返回 Diagnostic Agents,等待状态变为 Online,然后选择 Open Console。

在诊断结果中记录已安装工具的版本和镜像标识:

docker exec <agent-container> ngxdig version
docker inspect <agent-container> --format '{{.Image}}'

Kubernetes​

首先查找网关 Pod 所在的节点:

kubectl -n <gateway-namespace> get pod <gateway-pod> -o wide

在 Add Diagnostic Agent 中选择 Kubernetes,并设置:

  • Control Plane Address:代理 Pod 能够访问的 DP Manager TLS URL。
  • Node Name:上一步查询到的网关 Pod 所在节点。
  • Namespace:已存在且准入策略允许生成的宿主机 PID 访问和 Linux capabilities 的命名空间。
  • 按需设置 Name、Image 和 Certificate Validity Period。

选择 Generate,将完整清单保存为 diagnostic-agent.yaml。清单包含一个 Secret 和一个固定到所选节点的 Pod,不会在每个节点上部署代理。

应用清单并检查生成的 Pod,使用之前输入的命名空间和名称:

chmod 600 diagnostic-agent.yaml
kubectl apply -f diagnostic-agent.yaml
kubectl -n <agent-namespace> get pod <agent-pod> -o wide
kubectl -n <agent-namespace> logs <agent-pod> --tail=50

确认网关和代理位于同一节点。返回 Diagnostic Agents,在代理变为 Online 后选择 Open Console。如需检查其他节点,请为每个节点分别部署代理。如果网关迁移到另一个节点,请选择或部署该节点上的代理。

备注

CPU 性能分析需要使用代理能够看到宿主机 PID 命名空间的宿主机或虚拟机。kind 或 k3d 等嵌套容器节点的 PID 命名空间与内核的初始命名空间不同,不适合此 CPU 性能分析流程。代理显示 Online 仅表示已连接控制面,不代表能够采集 CPU 样本。

每次执行 Generate 都会签发新证书并创建独立的代理身份。再次生成不会替换或停止先前的部署。请保留部署文件,以便管理实际安装的容器或 Pod。

选择网关工作进程​

诊断终端会列出可见进程的 PID、角色、主进程 PID、CPU 使用率、RSS 和运行时长。请从待排查的网关中选择一个 worker。

对于 Docker,使用以下命令识别网关在宿主机上的进程 ID:

docker top <gateway-container> -eo pid,ppid,args

将这些进程 ID 与终端中的进程匹配。docker exec <gateway-container> ps 显示的 PID 位于容器命名空间中,可能不同于代理显示的宿主机 PID。具有相同主进程 PID 的工作进程属于同一个 NGINX 实例。不要仅因为某个进程是宿主机上最繁忙的进程,就选中另一个网关。

对于 CPU 问题,选择 CPU 使用率高的受影响工作进程。对于内存问题,先选择 RSS 较高或持续增长的工作进程。网关重启或重新加载后,工作进程 ID 可能变化,请刷新进程列表。

在进行 CPU 性能分析之前,检查采集环境:

# Docker
docker exec <agent-container> ngxdig doctor

# Kubernetes
kubectl -n <agent-namespace> exec <agent-pod> -- ngxdig doctor

解决 CPU 采集检查中失败的项目后再继续。BTF 或 eBPF 检查失败本身不会阻止采集内存快照。

采集 CPU 性能分析​

在 CPU 问题发生时进行采集。在测试部署中,采集期间应持续通过现有路由发送具有代表性的流量。几乎空闲的工作进程可能无法通过 CPU 预检,或产生的样本过少。

  1. 在诊断终端中选择目标工作进程。
  2. 在 Run Diagnostic 下,将 Command 设置为 cpu-on。
  3. 首次采集时,将 Duration seconds 设置为 30、Hz 设置为 100、CPU profile level 设置为 C + Kernel。
  4. 将 Format 设置为 html,然后选择 Run。
  5. 等待运行状态变为 succeeded,然后打开其 HTML 产物或选择 Download all。

报告包含 CPU 火焰图和采集质量信息。较宽的栈帧表示在该次采集中占据更多样本;横轴不是时间轴。沿较宽的调用栈定位 CPU 时间的消耗位置,并在得出结论前检查未解析的栈帧和质量警告。

即使运行成功,报告仍可能显示 Degraded 状态或 Low 质量。例如,受限的内核符号或不完整的原生栈展开会导致部分性能分析无法解析。请保留这些警告,不要将未解析的样本归因于某个具体函数。

终端将 C + Kernel + Lua 和 Lua only 标记为实验性选项。调查 Lua 执行时可以使用这些选项,并保留报告中的覆盖率和质量信息。缺少 Lua 栈帧不能证明 Lua 未消耗 CPU。

需要结构化 CPU 证据 JSON 时,选择 evidence 而不是 html。这会生成 JSON 产物而不是 HTML 报告。请下载 JSON,以供离线分析或技术支持使用。

一个代理一次只能运行一项采集。请等待当前运行结束后,再启动下一项。

采集内存快照​

内存快照描述某一工作进程在某个时间点的状态,也适用于空闲的工作进程。调查内存增长时,应在可比较的工作负载条件下,对同一工作进程采集基准快照和后续快照。

  1. 选择目标工作进程。
  2. 将 Command 设置为 memsnap。
  3. 将 Memory deep mode 保持为 best-effort,然后选择 Run。
  4. 运行成功后,打开 bundle/report.html 并下载完整文件包。
  5. 内存增长后再次采集。记录采集时间、流量情况以及任何配置变更。

文件包包含 report.html、memsnap.json、maps.csv 和 meta.json。请保留这四个文件:HTML 便于阅读,其他文件则保留测量值和采集上下文。

尽可能比较至少三次快照:两次快照只能显示差异,后续快照有助于区分一次性增长和持续增长。工作进程重启或重新加载后,当前比较序列即告结束;请为新进程建立新的基准。

解读内存报告​

结合置信度和警告字段阅读报告中的测量值:

多次快照中的现象排查方向
LuaJIT 已分配字节数(gc.total)持续增长LuaJIT 分配压力和大致的对象构成。该计数不能证明对象可达性或存在内存泄漏。
LuaJIT 分配器占用增加,但 gc.total 保持稳定分配器保留内存或内存碎片。仅凭这一点不能证明存在泄漏。
某个共享区域的已用字节数增加对应模块的共享内存使用量和容量。
私有匿名内存增加,但 LuaJIT 或共享区域没有相应增长原生分配或这些解码器未能归因的其他内存;请保留完整证据以便进一步分析。

RSS、PSS、LuaJIT 对象大小、分配器占用和共享区域大小衡量的是不同且相互重叠的内存维度。不要将它们相加,也不要在未考虑共享页面的情况下,通过累加各工作进程的 RSS 来估算网关的独占内存。

best-effort 会读取正在运行的工作进程。并发分配可能使解码器产生 partial 或降级结果,即使运行本身成功。请结合声明的置信度使用可用测量值;缺失或不受支持的测量值不等于零。

警告

consistent 内存模式会在读取内存时暂停目标工作进程,可能延迟该工作进程处理的请求。仅在确实需要一致快照,且允许短暂中断的时间窗口内使用。将 Max pause seconds 设置为有限值;0 表示不限制。常规流程使用 best-effort,不会主动暂停工作进程。

下载并保留结果​

在 Runs 中,使用 Download all 下载一次采集的全部结果,或选择多次运行后使用 Download selected 一并下载。在浏览器中打开下载的 HTML 报告;向技术支持分享结果时,请保留原始证据文件。

请附上网关版本、ngxdig 版本和镜像标识、宿主机或节点、工作进程 PID、症状时间窗口以及流量情况。分享前检查报告,因为进程详情、路径和运维数据可能包含敏感信息。不要包含部署命令、清单或 mTLS 私钥。

移除代理之前先下载结果。生成的 Docker 部署将结果保存在容器中,Kubernetes 部署使用 emptyDir 卷。删除容器或 Pod 可能导致这些结果丢失;控制台不是持久化报告归档。

故障排查​

症状检查与处理
代理始终为 Offline 或从未出现检查代理日志。检查 DNS、到 DP Manager TLS 端口的网络连通性、证书有效期和已配置的地址。代理连接后才会出现。
TLS 主机名校验失败使用证书涵盖的 DP Manager 地址,并确认控制面的 dp_manager_address 配置。修正配置后重新生成凭据;不要禁用 TLS 校验。
终端没有列出目标工作进程确认代理位于网关宿主机或节点上,且保留了 --pid host 或 hostPID: true。比较宿主机进程 ID,并在重启后刷新。
Kubernetes 拒绝代理 Pod检查 Pod 事件和准入错误。使用已获准访问宿主机 PID 并使用生成的 Linux capabilities 的命名空间。
CPU 采集因 BTF、权限或性能事件失败运行 ngxdig doctor。检查宿主机内核、/sys/kernel/btf 可见性、生成的 Linux capabilities 和运行时安全策略。
CPU 预检报告目标空闲或样本不足在问题发生且存在代表性流量时采集受影响的工作进程。确认所选 PID 属于该网关。
已有一项运行正在进行等待该代理上的运行结束后,再启动下一次采集。
内存采集无法读取 /proc/<pid>/mem 或 smaps_rollup确认 PID 仍然存在、已启用宿主机 PID 访问,且 SYS_PTRACE 和运行时安全策略允许读取工作进程。
内存解码器报告 partial、degraded 或 unsupported 数据保留文件包并检查警告。不要将不可用数据视为零,也不要因为运行成功就假定所有解码器都已成功。

移除代理​

下载报告后,按部署名称移除 Docker 代理:

docker rm -f <agent-container>

对于 Kubernetes,使用已保存的生成清单删除资源:

kubectl delete -f diagnostic-agent.yaml

代理停止采集后,最终会在控制台中显示为 Offline。删除其容器或 Pod 不会删除网关。