线上故障,这次是kube-proxy的锅

现象#

k8s 环境,假设调用链路是 A 调用 B。

  • A 调用 B 报超时错误
  • 服务 B 接口监控发现延迟正常(就好像 A 并没有调用 B 一样)
  • B 是 php 服务,阶段性出现 php_network_getaddresses: getaddrinfo failed 报错

分析#

DNS 问题?#

先从这个报错查起 php_network_getaddresses: getaddrinfo failed

搜索这个错误,谷歌、百度会告诉你 dns 解析的问题,解析失败会报这个错。

image-20211231204225990

但实际上,我们不论在 pod 里面还是在 node 机器上 ping 对应访问的域名,都是可以成功解析的。

排查陷入尴尬的境地,感觉是网络问题,为什么呢?

  • 上游请求下游,大量超时,但是下游却响应正常,感觉因为网络有问题,请求没有到达下游,或者下游返回的时候上游没有收到。
  • getaddrinfo failed 表示有时候 dns 解析有问题,但是能排除 dns 本身的问题,可能还是网络的问题,但是请求或者响应有问题。

网络问题?#

网络问题可能是哪些问题呢?

  • 带宽满了?

    • 不是,检查过 node 的带宽,虽然带宽占用挺高的,但是远没有达到上限

      image-20211231210551405

  • LB 超载了?

    • 不是,虽然问题期间链接数上升了不少,但是还是没有到达上限。目前主要问题是请求超时,因为请求不能快速结束,所以需要更多的链接,链接数上升也说得通。

      image-20211231211355372

机器问题?#

  • CPU、内存、负载高了?

    • 不是,指标正常

      image-20211231210706177

  • 看看 node 主机有没有报错?

    • demsg,看到有如下报错:dropping packet 不就是丢包的意思么?

      LSSHdauu1J

问题浮现#

现在定位的问题是 conntrack table 满了,导致丢包。那 conntrack 是什么呢?

conntrack连接跟踪,大概意思是 Linux 为每一个经过网络堆栈的数据包,生成一个新的连接记录项 (Connection entry)。此后,所有属于此连接的数据包都被唯一地分配给这个连接,并标识连接的状态。

查看 conntrack 的上限和当前值,上线是 52.4w,当前已经是 52.2w,已经接近上限了。

image-20211231212258139

执行命令 sysctl -w net.netfilter.nf_conntrack_max=2310720,提高上限,此时问题收敛。

问题复盘期间,运维同学提到 net.netfilter.nf_conntrack_max 这个值在去年的时候已经调整到 231w 了,为啥现在又变回来了?

考虑到 k8skube_proxy 组件和 conntrack 有绝对关系,然后谷歌了下,看到 kube-proxy 有几个相关的参数。

33j87MuF5A

看了下我们 kube-proxy 的启动命令 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=cn-beijing-xxx,配置文件是空的,也就是都是使用这些参数的默认值,--conntrack-max-per-core 代表每个 cpu 核跟踪的最大 NAT 数量,默认值是 32768。我们是 16核的机器,16*32768=524288,524288 和系统中的 net.netfilter.nf_conntrack_max 值是一致的。

net.netfilter.nf_conntrack_max 为啥变化了呢

运维同学很确定这个参数值在去年就修改过,这个事情我也有印象。继续谷歌,看到了这边文章《kube-proxy conntracker 设置》,大概意思是,kube-proxy 的启动参数中如果没有设置–conntrack-max 参数,则对比–conntrack-min 和–conntrack-max-per-core 的值与 cpu 核数的大小取其大者返回 max 值,默认值是 32768 * CPU 核数,最后调用 SetMax 设置 conntrack-max 的值

所以是 kube-proxy 重启的时候修改了系统的 net.netfilter.nf_conntrack_max 值。这是一个坑,不踩真的不知道。

再回想,昨天运维确实升级重启过 kube-proxy….

总结#

  • 上游请求下游,上游超时,下游响应正常,大概率是网络的问题。

  • 网络的问题,是 node 主机 conntrack 达到上限,导致丢包,丢包导致微服务请求超时。

  • net.netfilter.nf_conntrack_max 这个参数在 kube-proxy 启动的时候会重新设置,所以要设置好 kube-proxy 启动参数。

  • 再看到 php_network_getaddresses: getaddrinfo failed 报错,排除 dns 本省的问题,很可能就是网络丢包导致的

  • 阿里云已经有相关监控和告警了

    image-20211231215148806# 现象

k8s 环境,假设调用链路是 A 调用 B。

  • A 调用 B 报超时错误
  • 服务 B 接口监控发现延迟正常(就好像 A 并没有调用 B 一样)
  • B 是 php 服务,阶段性出现 php_network_getaddresses: getaddrinfo failed 报错

分析#

DNS 问题?#

先从这个报错查起 php_network_getaddresses: getaddrinfo failed

搜索这个错误,谷歌、百度会告诉你 dns 解析的问题,解析失败会报这个错。

image-20211231204225990

但实际上,我们不论在 pod 里面还是在 node 机器上 ping 对应访问的域名,都是可以成功解析的。

排查陷入尴尬的境地,感觉是网络问题,为什么呢?

  • 上游请求下游,大量超时,但是下游却响应正常,感觉因为网络有问题,请求没有到达下游,或者下游返回的时候上游没有收到。
  • getaddrinfo failed 表示有时候 dns 解析有问题,但是能排除 dns 本身的问题,可能还是网络的问题,但是请求或者响应有问题。

网络问题?#

网络问题可能是哪些问题呢?

  • 带宽满了?

    • 不是,检查过 node 的带宽,虽然带宽占用挺高的,但是远没有达到上限

      image-20211231210551405

  • LB 超载了?

    • 不是,虽然问题期间链接数上升了不少,但是还是没有到达上限。目前主要问题是请求超时,因为请求不能快速结束,所以需要更多的链接,链接数上升也说得通。

      image-20211231211355372

机器问题?#

  • CPU、内存、负载高了?

    • 不是,指标正常

      image-20211231210706177

  • 看看 node 主机有没有报错?

    • demsg,看到有如下报错:dropping packet 不就是丢包的意思么?

      LSSHdauu1J

问题浮现#

现在定位的问题是 conntrack table 满了,导致丢包。那 conntrack 是什么呢?

conntrack连接跟踪,大概意思是 Linux 为每一个经过网络堆栈的数据包,生成一个新的连接记录项 (Connection entry)。此后,所有属于此连接的数据包都被唯一地分配给这个连接,并标识连接的状态。

查看 conntrack 的上限和当前值,上线是 52.4w,当前已经是 52.2w,已经接近上限了。

image-20211231212258139

执行命令 sysctl -w net.netfilter.nf_conntrack_max=2310720,提高上限,此时问题收敛。

问题复盘期间,运维同学提到 net.netfilter.nf_conntrack_max 这个值在去年的时候已经调整到 231w 了,为啥现在又变回来了?

考虑到 k8skube_proxy 组件和 conntrack 有绝对关系,然后谷歌了下,看到 kube-proxy 有几个相关的参数。

33j87MuF5A

看了下我们 kube-proxy 的启动命令 /usr/local/bin/kube-proxy --config=/var/lib/kube-proxy/config.conf --hostname-override=cn-beijing-xxx,配置文件是空的,也就是都是使用这些参数的默认值,--conntrack-max-per-core 代表每个 cpu 核跟踪的最大 NAT 数量,默认值是 32768。我们是 16核的机器,16*32768=524288,524288 和系统中的 net.netfilter.nf_conntrack_max 值是一致的。

net.netfilter.nf_conntrack_max 为啥变化了呢

运维同学很确定这个参数值在去年就修改过,这个事情我也有印象。继续谷歌,看到了这边文章《kube-proxy conntracker 设置》,大概意思是,kube-proxy 的启动参数中如果没有设置–conntrack-max 参数,则对比–conntrack-min 和–conntrack-max-per-core 的值与 cpu 核数的大小取其大者返回 max 值,默认值是 32768 * CPU 核数,最后调用 SetMax 设置 conntrack-max 的值

所以是 kube-proxy 重启的时候修改了系统的 net.netfilter.nf_conntrack_max 值。这是一个坑,不踩真的不知道。

再回想,昨天运维确实升级重启过 kube-proxy….

总结#

  • 上游请求下游,上游超时,下游响应正常,大概率是网络的问题。

  • 网络的问题,是 node 主机 conntrack 达到上限,导致丢包,丢包导致微服务请求超时。

  • net.netfilter.nf_conntrack_max 这个参数在 kube-proxy 启动的时候会重新设置,所以要设置好 kube-proxy 启动参数。

  • 再看到 php_network_getaddresses: getaddrinfo failed 报错,排除 dns 本省的问题,很可能就是网络丢包导致的

  • 阿里云已经有相关监控和告警了

    image-20211231215148806

本作品采用《CC 协议》,转载必须注明作者和本文链接
您的点赞、评论和关注,是我创作的不懈动力。 学无止境,让我们一起加油,在技术的胡同里越走越深!