K8S IPVS模式下UDP流量无法按RR轮询分发及ipvsadm超时配置问题
IPVS内核模块原生将UDP超时参数的最小值限制为1,直接修改ipvsadm源码跳过参数校验将值设为0的方案无效——内核处理逻辑中0值会触发默认300秒UDP超时兜底,反而会加剧会话粘滞问题。要实现等价于禁用IPVS UDP超时、保障RR轮询正常生效的效果,可选择以下生产验证过的方案:
方案1:为UDP类型IPVS虚拟服务开启单包调度(最推荐)
IPVS原生支持--ops(One Packet Scheduler)参数,开启后不会为UDP流量维护任何会话连接表,每个到达的UDP报文都会独立触发RR调度逻辑,完全不受超时参数影响。
由于kube-proxy会周期性同步IPVS规则、覆盖手动修改的参数,可在所有节点部署周期任务(间隔10s即可)执行以下命令,自动为所有UDP虚拟服务加上ops标记:# 遍历所有UDP类型的IPVS虚拟服务,追加ops参数 ipvsadm -L -n --numeric | awk '/^UDP/ {print $2}' | while read vs_addr; do ipvsadm -E -u $vs_addr -s rr --ops done配置生效后可通过
ipvsadm -L -n查看对应虚拟服务条目,带ops标记即代表配置成功,此时UDP流量会严格按RR规则分发到后端,无任何会话粘滞。方案2:定时清理UDP连接跟踪条目,对齐1秒超时阈值
如果不方便修改IPVS虚拟服务参数,可通过主动清理连接跟踪条目的方式避免会话复用。在所有节点部署周期为500ms的定时任务,执行以下命令清理过期UDP连接:# 清理所有存在时间超过1s的UDP conntrack条目 conntrack -D -p udp --timeout 1同时调整内核参数关闭IPVS与conntrack的联动,避免条目残留:
sysctl -w net.ipv4.vs.conntrack=0 sysctl -w net.netfilter.nf_conntrack_udp_timeout=1 sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=1该方案下UDP连接的实际存活时间最长不超过1s,配合500ms的清理周期,可实现近似无状态的转发效果,RR调度不会出现持续粘滞同一后端的问题。
方案3:关闭Service层面的会话亲和性配置
首先排查所有UDP服务的会话亲和性配置,确保没有强制开启会话保持:# 检查所有Service的sessionAffinity配置 kubectl get svc -A -o yaml | grep -E 'name:|sessionAffinity:'若存在UDP服务的
sessionAffinity值为ClientIP,直接修改为None即可,避免kube-proxy主动为对应服务配置超长的会话保持时间,覆盖IPVS的超时配置。
注意:不建议通过重新编译内核的方式强行修改UDP超时下限,该操作会影响节点上所有依赖IPVS的服务,且内核版本迭代后需要重新适配,维护成本极高。
内容的提问来源于stack exchange,提问作者Piyush Badkul

