记录一次 K8s 环境中 DNS 解析延迟导致 WebClient 请求失败的排查过程
记录一次 K8s 环境中 DNS 解析延迟导致 WebClient 请求失败的排查过程
背景介绍
我们有一个运行在 Kubernetes 集群中的微服务应用,使用 Spring WebFlux
的 WebClient
模块调用一个外部系统接口:
WebClient.create().post().uri("https://ewc.example.com/ds/demo/projectProcess").bodyValue(request).retrieve().bodyToMono(Response.class).block();
某天,该接口频繁出现超时告警,查看日志发现大量如下异常:
org.springframework.web.reactive.function.client.WebClientRequestException: Failed to resolve 'ewc.example.com' [A(1)]at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:137)Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):*__checkpoint ⇢ Request to POST https://ewc.example.com/ds/demo/projectProcess [DefaultWebClient]
Original Stack Trace:at org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:137)
错误信息明确指向:DNS 解析失败。
初步分析
异常信息中的 Failed to resolve 'ewc.example.com'
表明域名无法解析。由于应用运行在 K8s Pod 中,其 DNS 解析流程如下:
Pod → CoreDNS → 上游 DNS → 权威 DNS → 返回结果
因此,问题可能出在:
- Pod 的 DNS 配置;
- CoreDNS 转发异常;
- 上游 DNS 服务不可达;
- 域名本身无法解析。
第一步:测试默认 DNS 解析
进入 Pod 执行:
time nslookup ewc.example.com
输出结果如下:
Server: 100.100.2.136
Address: 100.100.2.136#53Name: ewc.example.com
Address: 10.131.112.69real 0m0.829s
user 0m0.005s
sys 0m0.002s
✅ 域名能解析,但耗时高达 829ms,远高于正常水平(通常应 < 100ms)。
这说明:解析链路存在性能瓶颈。
第二步:验证公网 DNS 是否正常
怀疑是本地 DNS 问题,于是使用公共 DNS 测试:
time nslookup ewc.example.com 8.8.8.8
结果:
real 0m0.052s
✅ 仅用 52ms 成功解析,说明:
- 域名
ewc.example.com
是有效的; - 阿里云 DNS 或公网解析服务正常;
- 问题出在 内部 DNS 转发链路。
第三步:排查上游 DNS 配置
经确认,example.com
域名由 阿里云 DNS 托管,并且配置了 DNS 转发规则,将 *.example.com
的查询请求转发到一组内部 DNS 服务器。
阿里云控制台显示转发规则如下:
上游 DNS IP | 端口 | 状态 |
---|---|---|
10.131.65.20 | 53 | ✅ 可用 |
10.100.240.195 | 53 | ❌ 不可达 |
10.222.197.4 | 53 | ❌ 不可达 |
10.222.197.5 | 53 | ❌ 不可达 |
📌 关键发现:只有
10.131.65.20
是可用的,其余三个节点均无法访问。
第四步:验证单个上游 DNS 性能
我们手动测试每个上游 DNS:
# 测试坏节点
time nslookup ewc.example.com 10.100.240.195
# 结果:connection timed out# 测试好节点
time nslookup ewc.example.com 10.131.65.20
# 结果:real 0m0.027s
✅ 10.131.65.20
响应迅速,仅需 27ms。
第五步:分析 CoreDNS 日志
查看 CoreDNS Pod 日志:
kubectl logs -n kube-system coredns-xxxxx
发现大量错误:
[ERROR] plugin/errors: 2 ewc.example.com. A: read udp 10.244.x.x:53->10.100.240.195:53: i/o timeout
✅ 证实:CoreDNS 尝试向不可达的 10.100.240.195
发起 UDP 查询,导致超时。
根本原因
阿里云 DNS 配置了多个不可达的上游服务器,且使用轮询策略,导致部分 DNS 查询被转发到故障节点,引发整体解析延迟或失败。
具体链路如下:
Pod → CoreDNS → 阿里云 DNS → [轮询] → 10.100.240.195(超时)→ 10.131.65.20(成功)
由于 UDP 超时时间较长(通常 5~10s),即使最终能成功,也会导致应用侧因等待 DNS 解析而超时。
解决方案
- 清理无效的上游 DNS 配置:
- 登录阿里云 DNS 控制台;
- 删除
10.100.240.195
、10.222.197.4
、10.222.197.5
三个不可达的转发地址; - 仅保留
10.131.65.20
。
- 验证修复效果:
time nslookup ewc.example.com
结果:
real 0m0.031s
✅ 所有请求稳定在 30ms 内完成。
- 应用侧观察:
WebClientRequestException
异常消失;- 接口成功率恢复 100%。
关键结论
问题点 | 结论 |
---|---|
DNS 是否由 CoreDNS 管理? | ❌ 否。CoreDNS 只是转发代理,实际由阿里云 DNS 管理 |
是否按优先级查询? | ❌ 否。阿里云 DNS 和 CoreDNS 均使用轮询,不支持优先级 |
为什么延迟高? | 因为请求被转发到不可达的上游 DNS,等待超时 |
为什么手动指定就快? | 因为绕过了坏节点,直接访问可用 DNS |
经验总结
- 不要盲目配置多个上游 DNS
如果节点不可达,反而会降低整体解析性能。 - 定期审计 DNS 转发规则
清理已下线或网络不通的节点。 - 监控 DNS 解析延迟
在 K8s 集群中增加nslookup
健康检查探针,或使用 Prometheus + Blackbox Exporter 监控 DNS 延迟。 - 避免依赖“轮询”实现高可用
应使用健康检查机制(如 keepalived、DNS 负载均衡器)来保障上游服务可用性。 - 应用层可做容错优化
- 自定义
InetSocketAddress
或 DNS Resolver; - 增加 WebClient 重试机制;
- 对关键依赖做本地缓存。
- 自定义
参考资料
- Kubernetes DNS 配置文档
- CoreDNS 官方文档
- 阿里云云解析 DNS 产品页