Dan*_*gro 7 linux load-average
我在我的一台服务器上遇到了一个奇怪的问题。这是在具有一个专用 CPU 内核的 KVM VPS 上。
但是,在此期间 CPU 使用率实际上并没有增加,这也排除了 iowait 是原因:

它发生时似乎是周期性的(例如,在此图中,它大约每 20-25 分钟发生一次)。我怀疑有一个 cronjob,但我没有任何每 20 分钟运行一次的 cronjob。我也试过禁用我的 cronjobs 并且负载峰值仍然发生。
当 SSH 进入服务器时,我设法实际看到了这种情况……它的负载为 1.88,但 CPU 空闲率为 94%,iowait 为 0%(这可能是我预期的原因)
发生这种情况时,似乎没有很多磁盘 I/O。
我难住了。有任何想法吗?
所以我解决了这个问题......结果证明它是由我用来监视服务器的软件(Netdata)引起的。
Linux 每 5 秒更新一次平均负载。事实上,它实际上每 5 秒更新一次加上一个“滴答”
#define LOAD_FREQ (5*HZ+1) /* 5 sec intervals */
Run Code Online (Sandbox Code Playgroud)
* The global load average is an exponentially decaying average of nr_running +
* nr_uninterruptible.
*
* Once every LOAD_FREQ:
*
* nr_active = 0;
* for_each_possible_cpu(cpu)
* nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible;
*
* avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n)
Run Code Online (Sandbox Code Playgroud)
HZ是内核定时器频率,在编译内核时定义。在我的系统上,它是250:
% grep "CONFIG_HZ=" /boot/config-$(uname -r)
CONFIG_HZ=250
Run Code Online (Sandbox Code Playgroud)
这意味着 Linux 每 5.004 秒 (5 + 1/250) 计算一次平均负载。它检查有多少进程正在积极运行以及有多少进程处于不可中断的等待(例如,等待磁盘 IO)状态,并使用它来计算平均负载,随着时间的推移呈指数平滑。
假设您有一个进程每秒启动一堆子进程。例如,Netdata 从一些应用程序收集数据。通常,该过程将非常快并且不会与负载平均检查重叠,因此一切正常。但是,每 1251 秒(5.004 * 250),平均负载更新间隔将是一秒的精确倍数(即 1251 是 5.004 和 1 的最小公倍数)。1251 秒是 20.85 分钟,这正是我看到平均负载增加的时间间隔。我的猜测是,每 20.85 分钟,Linux 就会在多个进程正在启动并在队列中运行的确切时间检查平均负载。
我通过禁用 netdata 并手动查看平均负载来确认这一点:
while true; do uptime; sleep 5; done
Run Code Online (Sandbox Code Playgroud)
1.5 小时后,我没有看到任何类似的尖峰。峰值仅在 Netdata 运行时发生。
所以......最终......我用来监控负载的应用程序是造成它的原因。讽刺。他可以拯救他人免于死亡,但不能拯救他自己。
事实证明,其他人过去也遇到过类似的问题,尽管间隔不同。以下帖子非常有帮助:
在此处向 Netdata 开发人员报告:https : //github.com/netdata/netdata/issues/5234。最后,我不确定我是否将其称为错误,但也许 netdata 可以实现一些抖动,以便它不会精确地每秒钟执行一次检查。