我的一台服务器上遇到了一个奇怪的问题。这是一台拥有一个专用 CPU 核心的 KVM VPS。
但是,在此期间 CPU 使用率实际上并没有增加,这也排除了 iowait 是原因:
这种情况似乎具有周期性(例如,在这张图中,大约每 20-25 分钟发生一次)。我怀疑是 cronjob,但我没有每 20 分钟运行一次的 cronjob。我也尝试过禁用 cronjob,但负载峰值仍然会出现。
我在通过 SSH 进入服务器时确实看到了这种情况的发生……负载为 1.88,但 CPU 有 94% 处于空闲状态,iowait 为 0%(我预计这可能是原因)
当这种情况发生时,似乎没有大量的磁盘 I/O。
我被难住了。有什么想法吗?
答案1
所以我解决了这个问题...结果发现这是由我用来监控服务器的软件(Netdata)引起的。
Linux 每 5 秒更新一次平均负载。事实上,它每 5 秒加一个“滴答”更新一次
#define LOAD_FREQ (5*HZ+1) /* 5 sec intervals */
* 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)
HZ
是内核定时器频率,在编译内核时定义。在我的系统上,它是250
:
% grep "CONFIG_HZ=" /boot/config-$(uname -r)
CONFIG_HZ=250
这意味着每 5.004 秒(5 + 1/250),Linux 就会计算一次平均负载。它会检查有多少进程正在运行,有多少进程处于不可中断的等待状态(例如等待磁盘 IO),然后使用它来计算平均负载,并随着时间的推移以指数方式平滑它。
假设您有一个每秒启动一堆子进程的进程。例如,Netdata 从某些应用程序收集数据。通常,该过程会非常快,并且不会与平均负载检查重叠,因此一切都很好。但是,每 1251 秒(5.004 * 250),平均负载更新间隔将是 1 秒的精确倍数(即,1251 是 5.004 和 1 的最小公倍数)。1251 秒是 20.85 分钟,这正是我看到平均负载增加的间隔。我的有根据的猜测是,每 20.85 分钟,Linux 都会在启动几个进程并排队运行的确切时间检查平均负载。
我通过禁用 netdata 并手动观察平均负载来确认这一点:
while true; do uptime; sleep 5; done
一个半小时后,我没看到任何类似的尖峰。尖峰仅有的在 Netdata 运行时发生。
所以……最后……我用来监控负载的应用程序是造成这种情况的罪魁祸首。讽刺。他可以救别人一命,却救不了自己。
事实证明,其他人过去也遇到过类似的问题,尽管间隔不同。以下帖子非常有帮助:
- 每 7 小时对闲置机器进行定期高负载调查
- 了解 Linux loadavg 每 7 小时上升的原因
- Telegraf - 每 1 小时 45 分钟平均负载较高
- Linux 提交将平均负载计算改为每 5 秒 + 1 刻计算一次,而不是每 5 秒准确计算一次
在此向 Netdata 开发人员报告:https://github.com/netdata/netdata/issues/5234。最后,我不确定我是否会将其称为错误,但也许 netdata 可以实现一些抖动,这样它就不会每秒都精确地执行一次检查。