momo's Blog.

KubernetesCPU资源限制以及CPUThrottlingHigh告警问题

字数统计: 1.1k阅读时长: 4 min
2021/03/25 Share

前言

最近频繁收到服务器的告警

1
26.67% throttling of CPU in namespace monitoring for container node-exporter in pod node-exporter-kkmjf.

说是节流率已经达到了26%, 但是当我上线去查看监控的时候,发现当前的pod资源使用率是非常低的,远远低于限定指标,那这个告警到底是什么回事呢?

Kubernetes的CPU资源请求和限制的实现方式

Kubernetes 使用 CFS [1]
做CPU资源的限制, 此调度器是集成在内核当中。简单的来说,CFS是通过添加了重分配周期和占用周期, 当一个进程在重分配周期内获得的CPU时间达到了占用周期,那么这个进程将不会在被调度,直到下一个重分配周期.

而CPU资源,则通过shares进行权重分配,每一个CPU权重值为1024. 如果一个节点中有4 core,而某个进程的权重为1024,那么这么进程只能使用1个CPU.

k8s使用了cgoup进行资源管理, 详细信息存储在虚拟文件系统(/sys/fs/cgroup)中。如果是CPU则为/sys/fs/cgroup/cpu,cpuacct/*

从上图我们看到,cgroup继承了4096个CPU份额, 也就是100%的CPU权重. 往下再看,可以看到有user.slice,system.slice 这两个是为系统级别应用,和用户空间的程序分配的资源。而我们也可以看到, kubepods 这个是由k8s创建的,用于分配资源给Pod使用.

细心的朋友可以看到, 上图中前两个节点分别拥有1024个份额,而kubepod使用了4096个。 明明root节点中只有4096个份额,而下面3个子节点竟然使用了(6144).

实际上改值是逻辑值, 调度器(CFS)通过该值的比例来分配配额.

比如在这种情况下,前两个cgoup分别获得680个(1024/61444096), 而kubepod获得其余的*2736**个。但是在资源空闲情况下,前两个cgoup并不会使用所有的资源,调度器有避免浪费的机制,会把空闲的资源释放到全局池中.

CPU 限制

上面我们说过了, CFS 是通过周期来进行配额的管理, 在cgroup的目录下有这两个文件, cfs_period_uscfs_quota_us, 其中 cfs_period_us 用于定义时间段, 通常是100000us(100ms), 第二个cfs_quota_us 表示在周期中允许使用的配额.

假如说我们为节点限制200ms的配额, 在100ms的时间周期中,意味着可以使用2个时间周期, 也就是2个CPU. 如下图

而如果在100ms周期内, 使用配额超过200ms, 则就会触发限流操作.

让我们回到我们遇到的问题:

  • 先看一下yaml中限制的配额

    1
    2
    3
    4
    5
    6
    7
    resources:
    limits:
    cpu: 250m
    memory: 180Mi
    requests:
    cpu: 102m
    memory: 180Mi
  • 回到pod所在主机,查看cgroup的文件

    1
    2
    3
    4
    cat cpu.cfs_period_us 
    100000
    cat cpu.cfs_quota_us
    25000

我们可以看到, 周期时间是100ms, 配额是25ms, 也就是说这个节点可以使用1/4核的CPU资源。

1
2
3
4
5
6
7
cat cpu.stat
# 周期的重置次数
nr_periods 427054
# 被限流的周期次数
nr_throttled 55680
# 限流的持续时间, 假如说每个周期的配额是25ms,那每个周期就会被限制75ms,一共经历了几个限制周期就是 75 * 55680,不过我们注意一下单位,下方单位不是ms,而是ns
throttled_time 4491686389551

可以看到,这个容器被限流很多次已经占总周期的13%,

研究CFS的限流机制

推荐阅读这个文档: https://gist.github.com/bobrik/2030ff040fad360327a5fab7a09c4ff1

此文档详细测试了CFS在休眠间隔时间越久的情况下, 就会频繁的触发节流机制.

这是一个内核基本的bug,并且已经修复.参考这个: sched/fair: Fix bandwidth timer clock drift condition

以及大佬的更详细的分析[2][3]:

结尾

当前bug已经在最新的内核版本修复, 并且主流的系统版本已经想代码合并

  • Linux-stable: 4.14.154+, 4.19.84+, 5.3.9+
  • Ubuntu: 4.15.0-67+, 5.3.0-24+
  • Redhat Enterprise Linux:
    • RHEL 7: 3.10.0-1062.8.1.el7+
    • RHEL 8: 4.18.0-147.2.1.el8_1+
  • CoreOS: v4.19.84+

解决方案:

  1. 升级内核
  2. 删除CPU的limit
  3. 提高limit限制

参考文档

CATALOG
  1. 1. 前言
  2. 2. Kubernetes的CPU资源请求和限制的实现方式
    1. 2.1. CPU 限制
  3. 3. 研究CFS的限流机制
  4. 4. 结尾
  5. 5. 参考文档