找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4416

积分

0

好友

572

主题
发表于 2 小时前 | 查看: 3| 回复: 0

一、背景与现象

云栈社区的技术排障讨论里,这类“偶发网络抖动”经常被低估。我们最近也碰到一个很典型的现象:从业务 Pod 访问某个 ClusterIP 类型的 Service,十次里总有一次会卡住然后超时,或者偶发 Connection reset by peer。更奇怪的是,Ingress/SLB 入口正常,Pod IP 直连也正常,唯独“过一道 Service”就抽风。

因为偶发,监控图上的表现只是一个小毛刺,很容易被当成网络抖动忽略。但业务方反馈“下单偶尔失败”,我们决定把它彻底查清楚。

二、排查过程

第一步,确认 kube-proxy 跑在哪种模式:

# 看 kube-proxy 配置
kubectl -n kube-system get configmap kube-proxy -o yaml | grep mode
# mode: "ipvs"

# 到节点上直接看 IPVS 规则
ipvsadm -Ln
# 能看到 Virtual Service 和对应的 Real Server(Pod IP)

第二步,对比 endpoint 是否和 IPVS 规则一致:

# Service 对应的 endpoints
kubectl get endpoints <svc> -o wide
# IPVS 里实际的 RS 列表
ipvsadm -Ln | grep -A10 <cluster-ip>

滚动发布期间,我们发现:endpoints 已经摘掉旧 Pod,但 ipvsadm -Ln 里旧 RS 还在,且权重变成 0;而另一瞬间,新 RS 还没被加进来。这中间有几秒窗口,请求会被打到不存在的 RS 上。

第三步,看 kube-proxy 的同步节奏:

# kube-proxy 日志里关注 endpoint 到 ipvs 规则的刷新
journalctl -u kube-proxy -n 200 | grep -i "sync\|endpoint"
# 默认 --ipvs-sync-period=30s,意味着最长 30s 才全量刷新一次

第四步,进 IPVS 连接表看实际打到哪了:

# 查看当前 IPVS 连接,确认有没有打到已销毁的 RS
ipvsadm -Ln -c | grep <cluster-ip>
# 结合 conntrack 看新建连接是否被静默丢弃(见同系列 NTP 那篇的 conntrack 思路)

三、根因分析

kube-proxy 在 IPVS 模式下,是把 Service 翻译成 IPVS 的 Virtual Service,后端 Pod 作为 Real Server。它监听 Endpoints/EndpointSlice 变化,再 refresh IPVS 规则。关键在于刷新不是瞬时、也不是每次事件都全量

  1. 同步周期造成的时间窗。默认 --ipvs-sync-period=30s--ipvs-min-sync-period=10s。Pod 滚动销毁/新建时,endpoints 变了,但 IPVS 规则要等下一个同步周期才更新。这个窗口里,旧 RS 还在、新 RS 没来,或者反之,请求就会落到“悬空”的 RS 上,表现为偶发超时/reset。

  2. conntrack 兜底缺失。IPVS 做 SNAT/masquerade 依赖 netfilter conntrack。如果节点 conntrack 表被打满(短连接、NAT 出口常见),新建连接会被静默丢弃,叠加在上面的“偶发超时”上,雪上加霜。

  3. 滚动更新没先摘流量。如果 Pod 的 readinessProbe 没配好,旧 Pod 还在 endpoints 里就被杀掉,或者新 Pod 没 ready 就被加进来,放大了 IPVS 规则与实际后端的错位。

本质是:Service 转发的“控制面”(endpoint 同步)和“数据面”(实际 Pod)在短时间内出现了视图不一致

四、解决方案

调小 kube-proxy 的 IPVS 同步周期,让规则跟 endpoints 变化贴得更紧:

# kubectl -n kube-system edit configmap kube-proxy
apiVersion: kubeproxy.config.k8s.io/v1alpha1
kind: KubeProxyConfiguration
mode: "ipvs"
ipvs:
  # 最小同步间隔和全量同步间隔都调小,缩短视图不一致的窗口
  minSyncPeriod: 5s
  syncPeriod: 15s
  # 严谨场景可开启,RS 消失时立即把相关连接置为异常,避免打到死 RS
  expireNonActiveConn: true

滚动更新侧,让 endpoint 先摘流量再杀进程(呼应之前《滚动更新 502 抖动》那篇):

spec:
  template:
    spec:
      containers:
      - name: app
        readinessProbe:
          httpGet: { path: /healthz, port: 8080 }
          initialDelaySeconds: 5
          periodSeconds: 5
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh","-c","sleep 15"] # 给 endpoint 摘流量留缓冲
      strategy:
        rollingUpdate:
          maxSurge: 1
          maxUnavailable: 0

如果节点 conntrack 压力大(IPVS 大规模集群常见),顺手调一下:

# 调大 conntrack 表,缩短 TIME_WAIT 占用
sysctl -w net.netfilter.nf_conntrack_max=262144
sysctl -w net.netfilter.nf_conntrack_tcp_timeout_time_wait=30

验证:ipvsadm -Ln -c 里看到连接都打到 ready 的 RS;滚动发布期间抓包确认没有请求落到已销毁 Pod;超时毛刺消失。

五、复盘与预防

  • 监控:暴露 kube-proxy 的 rest_client_requests_total(看 endpoint 同步频率)、节点 node_time_seconds 漂移;用 ipvsadm -Ln -c 巡检有无打到 FIN_WAIT/SYN_SENT 卡死的连接。

  • 告警:endpoints 的 ready 地址数与 Pod ready 数不一致,持续 30s 就告警;Service 成功率低于 99.9% 直接告警而非等毛刺。

  • 规范:所有被 Service 暴露的服务必须配 readinessProbe + preStop;IPVS 集群把 minSyncPeriod 写进 kube-proxy 标准配置。

  • 压测:发布窗口做“滚动更新 + 持续压测”,提前暴露 endpoint 与 IPVS 规则错位。

  • 修复验证:连续两次滚动发布零超时毛刺、IPVS 连接表无悬空 RS,才算真正闭环。

六、小结

IPVS 模式性能比 iptables 好,但代价是“规则同步有周期”。只要把同步周期调小、滚动更新先摘流量、conntrack 别打满,偶发超时基本能消除。

后续我们还会继续展开一个 Ingress 高频坑:路径 rewrite 没写对,后端收到错误 path 直接 404。




上一篇:别把降薪入职当过渡:从7000到3000的程序员职场反思
下一篇:C# 开源视觉框架 InsightFactory:视觉检测与 PLC 联动的插件化解耦实践
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-8-31 07:13 , Processed in 1.241335 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表