一、问题背景
某生产 Kubernetes 集群(v1.28,containerd 运行时,Calico CNI)承载了约 200 个微服务 Pod,分布在 12 个 worker 节点上。近期业务团队反馈:部分 Pod 之间的 HTTP/gRPC 调用出现间歇性超时,频率大约每小时 2-3 次,每次持续 10-30 秒后自动恢复。因为不是持续故障,问题排查起来格外棘手。
二、故障现象
业务方反馈的现象汇总如下:
- 受影响的服务:主要集中在某两个节点上的 Pod,调用其他节点上的服务时偶发
connection timeout - 时间规律:无明显时间段规律,白天和凌晨都有发生
- 恢复方式:无需人工介入,10-30 秒后自动恢复正常
- 影响范围:仅影响新建 TCP 连接,已建立的连接不受影响
- 监控表现:Prometheus 监控显示对应时间段内 Pod 的
container_network_receive_errors_total和container_network_transmit_errors_total均有异常增长
初步怀疑方向:CNI 插件问题、kube-proxy 异常、或者底层网络设备丢包。
三、排查过程
3.1 排除 CNI 层
首先检查 Calico 状态:
|
|
所有节点 BGP peer 状态正常,无异常日志。calicoctl get ippool -o wide 确认 IPAM 未耗尽。
在受影响节点上抓包:
|
|
发现一个关键现象:Client Pod 发出的 SYN 包确实到达了宿主机网卡,但没有进入目标容器的 veth pair。这意味着丢包发生在宿主机内核网络栈层面。
3.2 检查内核日志
|
|
输出直接揭示了根因:
|
|
conntrack 表满了! 内核在 conntrack 表容量耗尽时,会直接丢弃新连接的 SYN 包,导致客户端 TCP 连接超时。
3.3 深入分析 conntrack 使用情况
查看当前 conntrack 条目数:
|
|
果然是打满了。再查看 conntrack 条目的构成:
|
|
发现大量 TIME_WAIT 状态的连接条目,且主要来自几个特定的源 IP —— 对应一台高频调用外部 API 的数据同步服务。
进一步查看 conntrack 超时参数:
|
|
TIME_WAIT 状态默认超时 120 秒,在连接量大的场景下,这个时长足以让 conntrack 表被 TIME_WAIT 条目迅速填满。
3.4 确认问题节点
对比各节点的 conntrack 使用率发现,问题节点运行了一个高频 HTTP 调用的数据同步 Pod,每秒向外发起约 800-1000 个短连接请求。每个请求完成后进入 TIME_WAIT,在 120 秒内堆积的条目数:
|
|
加上其他 Pod 的正常连接追踪条目(约 14 万个),轻松突破默认的 262144 上限。
四、解决方案
4.1 紧急处理(不中断业务)
立即调整 conntrack 表大小:
|
|
表大小翻倍后抖动立即消失。
4.2 降低 TIME_WAIT 超时
|
|
4.3 启用 TCP 连接复用
指导业务方在高频调用服务中启用 HTTP Keep-Alive 和连接池:
|
|
Keep-Alive 复用连接后,新建连接速率从 1000/秒下降到约 80/秒,conntrack 压力直接降低了 90% 以上。
4.4 增加监控告警
在 Prometheus 中添加 conntrack 使用率告警规则:
|
|
五、根因分析
本次问题的根因链条:
- 应用层:数据同步服务使用短连接方式调用外部 API,未启用连接池复用
- TCP 协议层:每个短连接断开后进入 TIME_WAIT 状态,持续 120 秒
- 内核层:conntrack 模块为每个 TCP 连接维护追踪条目,TIME_WAIT 条目在超时前不会被回收
- 资源瓶颈:默认 conntrack_max=262144,在 1000 cps 的场景下,仅 TIME_WAIT 就占用了近一半容量
- 故障表现:conntrack 表满后内核丢弃新 SYN 包,TCP 客户端多次重传超时后报 connection timeout
本质上是一个应用层设计缺陷(短连接)被底层内核资源限制(conntrack 表大小)放大的典型案例。
六、预防措施
-
应用层面:所有服务间调用默认启用连接池和 Keep-Alive,避免短连接模式。Code Review 阶段增加连接复用检查项。
-
内核参数标准化:将以下参数纳入节点初始化基线 ——
1 2 3net.netfilter.nf_conntrack_max = 524288 net.netfilter.nf_conntrack_tcp_timeout_time_wait = 60 net.netfilter.nf_conntrack_tcp_timeout_established = 86400 -
conntrack 监控:所有 K8s 节点接入 conntrack 使用率监控,设置 80% 预警、95% 严重告警。
-
容量规划:根据节点上预期 Pod 数量和连接模型,提前计算 conntrack 需求:
1预期条目数 ≈ Pod数量 × 平均连接数 × 连接超时/平均连接时长 -
定期巡检:将
conntrack -S输出纳入日常巡检脚本,关注insert_failed(插入失败计数)的增长趋势。
七、总结
conntrack 表满是一个典型的"静默故障"——不会触发明显的错误日志,监控面板上可能只是偶尔几个超时曲线的小抖动,容易被忽视。但一旦触发,影响面很大,且排查依赖 dmesg 内核日志和 conntrack 工具的熟练使用。
这次排查再次印证了一个原则:在排查 K8s 网络问题时,不要只盯着 CNI 和 Service 层,宿主机内核网络栈的参数同样是关键变量。 很多时候问题的根因不在容器编排层,而在更底层的内核资源配置上。
调整后的集群运行至今再未出现类似问题,conntrack 使用率稳定在 40%-55% 之间。