跳转至

eBPF 排查 DNS 与 UDP 异常

DNS 返回了错误、DNS 没有观测到响应和 UDP socket 发送失败,是不同层面的事实。本篇用实际样本展示如何分别处理,并说明什么时候不能归属到具体进程或对端。

实测环境与查询入口见 网络排障实践总览。UDP socket 采集需要 enable_udp=true;DNS 还要检查独立的 dns_capture_available 与抓包损失。当前诊断只解析可观测的明文 DNS,不能展示 DoH/DoT 中的查询内容。

场景一:解析器明确返回 SERVFAIL

下面是实测日志 message 解析后的关键字段节选:

{
  "schema": "ebpf_network_event/v1",
  "entity": {
    "scope": "dns_transaction",
    "netns": "4026531840",
    "protocol": "udp",
    "role": "client",
    "role_source": "dns_query",
    "local_ip": "10.23.0.1",
    "remote_ip": "10.23.0.1",
    "service_port": 53
  },
  "problem_type": "dns_error_response",
  "occurrences": 1,
  "evidence_partial": false,
  "samples": [
    {
      "local": "10.23.0.1:55171",
      "remote": "10.23.0.1:53",
      "stage": "dns",
      "detail": "query=failure.example.test type=A rcode=2; capture observes plaintext DNS only"
    }
  ]
}

采集确认 failure.example.test 的 A 查询收到 rcode=2,解析器地址为 10.23.0.1:53。根据 RFC 1035 的 DNS 返回码,2 表示服务器失败,3 表示域名不存在。故障注入同时测试了正常 NXDOMAIN 查询 missing.example.test,不会仅因为返回 NXDOMAIN 就发故障线索。

SERVFAIL 提示从解析器和它的上游链路检查;它不是“UDP 报文丢了”的证据。样本范围为 dns_transaction,没有 PID,因此只能先归属到网络命名空间和 DNS 端点,不能宣称已经定位到具体应用进程。根据实际域名和业务错误,进一步区分合法的负查询、上游不可达、区域配置或权限问题。

Kubernetes 中先做只读检查:

kubectl -n kube-system get service kube-dns -o wide
kubectl -n kube-system get endpointslice -l kubernetes.io/service-name=kube-dns -o wide
kubectl -n kube-system get pods -l k8s-app=kube-dns -o wide
kubectl -n kube-system logs -l k8s-app=kube-dns --since=10m --tail=200

在受影响业务环境中核对 /etc/resolv.conf 和同一个完整域名的解析结果;检查 CoreDNS 日志、配置和上游,而不是先全局开启逐查询日志。对应的 Service、EndpointSlice 和 CoreDNS 排障步骤见 Kubernetes DNS 排障。

修复后按同一查询名/类型、解析器和命名空间复测,确认错误响应增量下降、解析得到预期结果;业务依赖不存在域名时,则应修正业务配置,不能把“清除所有 NXDOMAIN”作为目标。

场景二:6 秒没有匹配到 DNS 响应

{
  "schema": "ebpf_network_event/v1",
  "entity": {
    "scope": "dns_transaction",
    "netns": "4026531840",
    "protocol": "udp",
    "role": "client",
    "role_source": "dns_query",
    "local_ip": "10.23.0.1",
    "remote_ip": "10.23.0.1",
    "service_port": 53
  },
  "problem_type": "dns_no_response",
  "occurrences": 1,
  "evidence_partial": false,
  "samples": [
    {
      "local": "10.23.0.1:51917",
      "remote": "10.23.0.1:53",
      "stage": "dns",
      "detail": "query=silent.example.test type=A; no matching response observed within 6s, not proof of a dropped datagram"
    }
  ]
}

这条记录确认采集器看到了 silent.example.test 的 A 请求,但在 6 秒内没有匹配到响应。它与明确的错误响应不同;evidence_partial=false 说明该记录没有已知的对应证据缺口,仍不代表端到端抓包绝对完整,也不证明数据报在网络上丢失。

按以下顺序缩小范围:

  1. 检查同一时段的 dns_capture_available、capture_loss_total/capture_unavailable_total 和采集摘要;抓包损失会清除待匹配项,避免制造 DNS 无响应样本,但没有损失计数也不能证明每一跳都被观测。
  2. 按 netns 与 DNS 端点确认是否集中在某个业务命名空间、节点或解析器;不能只查节点默认命名空间。
  3. 对齐 CoreDNS 的接收、处理延迟与上游查询,检查是否是解析器排队、上游慢或传输路径问题。
  4. 用少量受影响请求复测;必要时短时、定向抓 DNS 数据,避免在全节点持续抓包。

dns_slow 的至少 1 秒阈值也是信息级线索。慢响应、无响应和错误响应应该分开统计,再按业务允许的解析时延设置平台告警。单独的静默窗口不能证明 DNS 已恢复。

场景三:UDP 发送返回消息过大

{
  "schema": "ebpf_network_event/v1",
  "entity": {
    "scope": "socket",
    "netns": "4026531840",
    "pid": 124,
    "process_name": "fixture",
    "service": "fixture",
    "protocol": "udp",
    "role": "unknown",
    "role_source": "unknown"
  },
  "problem_type": "io_message_size",
  "occurrences": 1,
  "evidence_partial": true,
  "samples": [
    {
      "stage": "send",
      "errno": -90,
      "detail": "UDP I/O error; original datagram destination unavailable, peer attribution omitted"
    }
  ]
}

errno=-90 对应 EMSGSIZE。这次实测来自故意发送超大的 UDP 消息,能确认本地 fixture 进程的发送错误,不能用这个实验宣称已验证某条生产路径存在 MTU 黑洞。

Linux UDP 会使用路径 MTU 信息,并可能向应用返回之前数据报的异步错误。因此该样本保留 socket/进程归属,省略无法确认的远端,且 evidence_partial=true;不能把错误强行归给最近一次发送的目的地址。协议行为见 udp(7)。

先检查实际消息长度、应用协议限制和错误处理。长度正常但故障集中在特定路径时,再对齐业务路由、隧道 MTU、ICMP “报文过大”线索及端到端探测。不要把单条 EMSGSIZE 直接认定为 MTU 问题,也不要默认关闭 PMTU 来掩盖原因。修复后用相同消息大小和路径确认发送成功、相关错误不再增加。

UDP、网络栈和网卡数据如何补充

下面是教学示例,用于说明归属层级,不是实测值:

60 秒内观测 教学增量 排查方向
某 netns 的 UDP 接收缓冲区错误 +120 核对该命名空间 socket 缓冲区、应用消费和突发负载
同一 netns 的无监听端口 +8 检查目标端口、服务重启和目标配置
同一 netns 的 ICMP 不可达 +8 核对可达性;不能与上一行相加当作 16 次独立丢包
某接口接收丢弃 +200 检查具体接口、驱动和节点资源,再对齐时间与业务流

这些是命名空间或接口层的来源计数,不是某个 socket 的精确丢包率。多个计数可能描述同一现象,接口还可能同时承载很多业务。默认节点指标汇总异常;对应异常日志保留来源范围。需要持续看每个命名空间/网卡时,可在少量节点开启完整指标模式,见 采集可信度与资源控制。

这类数据能把“域名或 UDP 有问题”分成解析结果、等待响应、socket 错误和网络栈压力。无法确认的 PID、UDP 远端或具体丢包位置保持未知,避免给出错误归因。

文档评价

文档内容是否对您有帮助?