Atlantis
GitHub Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

6. 节点心跳超时

1. 前言

集团内部用户在私有云上使用 ECS 自建了 K8s 集群,使用过程中经常出现节点 NotReady,客户坚持在云下环境没有问题,到了信创云上才出现的,于是问题给到了计算部门,排障任务来到了我这里。

从结果来讲,客户的集群配置未做优化,而 ECS 也存在性能问题(ARM 64 位处理器的性能不足),排查过程中重新学习了一遍节点心跳机制,这里做个记录。

2. STAR

2.1 Situation

集团内部客户在私有云上使用 ECS 自建了一个 K8s 集群,业务运行一段时间后,出现工作节点频繁 NotReady,节点上的 Pod 被驱逐的情况,严重影响业务,客户自行排查无果,将问题归结于私有云,于是主管们拉了一个群解决问题。

2.2 Task

协助用户定位节点频繁 NotReady 原因,保障业务稳定运行。

2.3 Action

节点 NotReady 的直接原因是被 kube-controller-manager 判定为离线,这说明节点长时间未发送 lease 与 status,NotReady 一段时间后,该节点上的 Pod 会被标记成 NotReady,随后触发 Pod 驱逐。

这篇博客已经很好地讲述了节点心跳机制的问题,不过缺少使用 lease 的情况:Kubelet 状态更新机制

alt text

我们需要进一步研究源码进行分析。

2.3.1 kubelet

  1. kubelet 每 10 秒钟更新一次 status
  2. 本地 status 发生变化时,立刻上报 status
  3. 本地 status 没有变化时,每 5 分钟才会上报一次状态,期间都是更新 lease,lease 的持续时间是 40s

alt text

alt text

我们可以使用 -w 开启 watch 来监听 kube-node-lease 命名空间下的 lease 资源:

alt text

2.3.2 kube-controller-manager

kube-controller-manager 的 node_lifecycle_controller 会缓存节点的 lease 和 status,并以固定间隔检测,只要检查到节点的 lease 或者 node.Status 在超时时间内更新过,就判断节点是 Ready 状态,否则判定为 NotReady。

alt text

alt text

alt text

总结下来就是:

  1. 固定执行间隔:node-monitor-period,默认5s
  2. 节点心跳超时时长:node-monitor-grace-period,默认40s,从最后一次 lease 或 status 上报开始算
  3. 节点启动超时时长(集群 bootstap 或节点创建):node-startup-grace-period,默认 1m0s,从节点创建开始算
  4. pod 驱逐超时时长:pod-eviction-timeout,默认 5m0s,从 NotReady 开始计算

2.3.3 客户的问题

定位问题的过程也比较复杂,隔壁部门协助排查的同事定位到 etcd 日志中读写请求时间较长(存在 1s、2s、10s 的写入时长),判定是磁盘 IO 性能不足,于是经过一些操作后暂时解决了问题,结果间隔一天客户再次报障。

这个时候客户已经比较焦躁,如果无法解决问题就要下云了(也许他们本来的目的就是业务不上私有云)。

于是我继续沿着之前的思路排查配置,最后确认了三个问题:

kube-controller-manager配置问题

集群 kube-controller-manager 的 node-monitor-grace-period 从 40s 调整到 10s了,由于 lease 也是 10s 上报一次,因此有概率出现误判的情况:

alt text

从 kube-controller-manager 的日志可以看到节点的状态反复切换,节点上的 Pod 状态随之跳动,那么通过 Service 访问 Pod 的请求也会异常:

alt text

确认配置问题后老板们也开始发话,纷纷表示心跳超时需要设置成心跳间隔的 3 倍以上。

master负载过高导致限流

客户的 Pod 都开启了 LivenessProbe,也是 10s 探测一次(触发一次查询 Pod 和一次更新 Pod 状态),排查 kubelet 日志发现大量 Throttling Request,最后确认 master 的负载过高,16 核 VM 的负载经常超过 18。

alt text

alt text

kubelet 在请求 kube-apiserver 时,如果等待时长超过 50ms 和 1s,会分别打印不同级别的日记,服务端则是有默认限制,按写和读的并发数限制:

alt text

集群架构规划不合理

集群中有 3 台 matser,其中一个绑定 VIP 来暴露 kube-apiserver,这个 VIP 同时作为内部和外部的入口,导致压力始终集中于一个 master,如果使用负载均衡器的话就能分流请求到 3 个 master:

alt text

2.3.4 ECS性能问题

在最开始得知客户使用 信创处理器 + 信创系统 后,我就预感会出现性能问题与内存问题,只是没想到这次是性能不足。客户自建集群的 etcd 也是运行在 master 上,在调整了磁盘 IO 性能,依旧出现读写请求时间过长问题,显然是 CPU 负载过大。

信创处理器分为 x86 与 ARM64 两种,前者主要是海光处理器,源于 AMD 的 Ryzen 一代,后者种类就比较多,但一般架构很老,连 AES 指令集都不具备,遇到性能敏感的场景就要扑街了。

从客户的配置可以看出来,他们比较关注 Pod 与 Node 的在线状态,因此设置了较低的存活检查时间间隔与超时阈值,结果产生了大量的访问 kube-apiserver 的请求,最终压力全部给到 etcd。他们原先可能使用配备 SSD 的 x86 物理机部署的集群,即使 kube-controller-manager 配置不当也能让 etcd 兜底。

etcd 性能不足导致问题在后面也出现过一次,首先是客户发现无法通过 service 访问到后端 pod,值班同学介入排查发现 endpoints 无法更新,然后我继续排查发现 kube-controller-manager 选举超时,原因是访问 kube-apiserver 的请求异常,最后确认 etcd 所在的 VM 使用了 IO 性能较差的高效云盘。

2.4 Result

将问题与解决方案整理提交给后,客户放弃自建,选择使用私有云的容器集群产品。