问题背景
谋客户反馈ingress偶发性健康检查失败问题,nginx-ingress-controller" failed (failure): Get "http://xx.xx.xxx.xx:10254/healthz": context deadline exceeded (Client.Timeout exceeded while awaiting headers)。
排查过程
重传较高,其中rto引发的重传较多,fastretrans有降低。
passiveopens和activeopens显著降低。
listenoverflow指标没有明显变化。
其他包括socket wqueue和rqueue堆积等监控客户未获取到,此外还能看到conntrack相关的查找数和softnet流量显著降低。以上监控表明客户的健康检查失败问题并非流量突增导致的,单个pod的流量突降可能的原因有:
● ingress off-cpu事件久问题。
● cgroup限制。
根因原理
cgroup cpu出现throttled现象。
容器的核心原理之一在于使用cgroup限制进程使用的资源,其核心原理在于调度时根据cgroup维护的cfs_rq决定是否按照cfs调度算法正常进行程序的调度:
// 每次出现cpu上下文切换或者hrtimer定时器触发是都会检测单个cfs_rq的时间偏是否小于0 // 如果已经小于0,即使用cpu超过配额,会设置throttle static void check_enqueue_throttle(struct cfs_rq *cfs_rq) { /* ensure the group is not already throttled */ if (cfs_rq_throttled(cfs_rq)) return; /* update runtime allocation */ account_cfs_rq_runtime(cfs_rq, 0); if (cfs_rq->runtime_remaining <= 0) throttle_cfs_rq(cfs_rq); } // 在执行enqueue到调度队列操作时,会根据cfs_rq的throttled来决定是否真正做enqueue操作 static void enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) { for_each_sched_entity(se) { cfs_rq = cfs_rq_of(se); pdate_load_avg(cfs_rq, se, UPDATE_TG); se_update_runnable(se); update_cfs_group(se); cfs_rq->h_nr_running++; cfs_rq->idle_h_nr_running += idle_h_nr_running; if (cfs_rq_is_idle(cfs_rq)) idle_h_nr_running = 1; /* 这里会根据task_struct的cgroup找到对应css_set的task_group调度实体,从而获取到cfs_rq */ if (cfs_rq_throttled(cfs_rq)) goto enqueue_throttle; } enqueue_throttle: assert_list_leaf_cfs_rq(rq); hrtick_update(rq); }
用户进程出现被cgroup进行throttle现象时,等同于无法被调度,即调度出现卡顿,用户程序执行会变慢。
在cpu子系统的statistic数据中:
● - nr_periods:已经过去的执行间隔的数量。
● - nr_throttled: 该组已被节流/限制的次数。
● - throttled_time: 该组的实体被限流的总时间长度(纳秒)。
对于网络操作来说:
● -收包操作,在内核上下文中执行,不会被cgroup throttle影响。
● -发包操作,由用户态程序trap到内核态进行操作,会被cgroup throttle影响。
综上原理,当cgroup throttle出现时,会造成的现象是:
● 用户态程序不会及时从socket rqueue中获取已经送达的报文,即。
● 用户态程序已经写入到socket wqueue的报文,由于nagle算法,tcp small queue等原因在内核生成报文当时还未发送的报文堆积,造成类似于“数据包无法打到对端”的类似现象,即RTO重传较高,但是乱序引发的fast retrans重传反而会降低。
上述两个现象进一步会造成:
● 握手失败,如健康检查失败等等。
● 会话超时,如ingress 出现499等。
解决办法
● 对于独占节点的服务如ingress等,不需要通过requests/limits进行资源限制,由于cfs算法的公平逻辑,偶发的cpu飙升出现的短暂卡顿并不会导致整个节点的持续性负载过高,但是对于ingress这样网络敏感的服务,容易引发偶发的网络问题从而影响业务。
● 如果客户对于放开限制有疑问的话,可以建议客户使用
https://www.alibabacloud.com/help/zh/container-service-for-kubernetes/latest/use-cpu-burst-to-improve-container-performance,通过slo-manager的方式提供cpu burst的能力。
● 如果客户没有采用ACK Pro,
可以参考https://help.aliyun.com/document_detail/306980.html,对cgroup本身进行允许burst的配置,但是此方式需要客户自行操作。
FAQ:为什么CPU整体占用率较低,还是会有throttled现象?
从上方介绍cgroup限制cpu的原理可以发现,cgroup统计计算一段时间内的vruntime分配情况来决定是否进行CPU限制,而常见的CPU使用率判断方式是根据一段时间内用户程序ONCPU状态的采样统计计算获得,是一个采样周期内的平均估算,因此出现偶发的CPU上升波动引发throttle与整体的CPU使用率不高没有直接的互斥关系。