为什么我的 Linux 系统会卡顿,除非我不断地删除缓存?

Pne*_*cat 6 memory linux performance cache

在过去的几个月里,我的 Linux 系统遇到了一个非常恼人的问题:它在 Firefox 音频播放、鼠标移动等方面卡顿,每隔几秒就会出现亚秒级(但仍然很明显)的卡顿。当内存缓存填满时,或者当我运行高度磁盘/内存密集型程序(例如备份软件restic)时,问题会恶化。然而,当缓存未满时(例如,在非常轻的负载下),一切都运行得非常顺利。

查看perf top输出,我发现list_lru_count_one在这些滞后期间有很高的开销(~20%)。htop还显示kswapd0使用了 50-90% 的 CPU(尽管感觉影响远大于此)。在极度滞后期间,htopCPU 仪表通常由内核 CPU 使用率决定。

我发现的唯一解决方法是强制内核保留可用内存 ( sysctl -w vm.min_free_kbytes=1024000) 或通过echo 3 > /proc/sys/vm/drop_caches. 当然,两者都不是理想的,也都不能完全解决口吃问题;它只会使它不那么频繁。

有没有人对为什么会发生这种情况有任何想法?

系统信息

  • i7-4820k 带有 20 GB(不匹配)DDR3 RAM
  • 转载于 Linux 4.14-4.18 on NixOS 不稳定
  • 在后台运行 Docker 容器和 Kubernetes(我觉得这不应该造成微口吃?)

我已经尝试过的

  • 使用多队列 I/O 调度程序更改 I/O 调度程序 (bfq)
  • 使用-ckCon Kolivas的补丁集(没有帮助)
  • 禁用交换,改变交换,使用 zram

编辑:为清楚起见,这里的图片htopperf这样的滞后穗期间。请注意高list_lru_count_oneCPU 负载和kswapd0+ 高内核 CPU 使用率。

htop 和 perf 输出

Pne*_*cat 3

问题已经找到了!

\n\n

事实证明,当存在大量容器/内存 cgroup 时,Linux 内存回收器会出现性能问题。(免责声明:我的解释可能有缺陷,我不是内核开发人员。)该问题已在此补丁集中的4.19-rc1+ 中修复:

\n\n
\n

此补丁集解决了在具有许多收缩器和内存 cgroup(即具有许多容器)的计算机上发生的收缩_slab() 缓慢的问题。问题是shrink_slab()的复杂度是O(n^2)并且随着容器数量的增长它增长得太快。

\n\n

让我们有 200 个容器,每个容器有 10 个挂载点和 10\n 个 cgroup。所有容器任务都是隔离的,并且它们不接触外部容器挂载。

\n\n

在全局回收的情况下,任务必须遍历所有 memcgs 并\n 为所有这些调用所有 memcg 感知的收缩器。这意味着,任务必须为每个 memcg 访问 200 * 10 = 2000 个收缩器,并且由于有 2000 个 memcg,因此 do_shrink_slab() 的调用总数为 2000 *\n 2000 = 4000000。

\n
\n\n

我的系统受到的打击特别严重,因为我运行了大量容器,这可能是导致问题出现的原因。

\n\n

我的故障排除步骤,以防它们对面临类似问题的任何人有帮助:

\n\n
    \n
  1. 注意kswapd0当我的计算机出现卡顿时,会使用大量 CPU
  2. \n
  3. 尝试停止 Docker 容器并再次填充内存 \xe2\x86\x92 计算机不会卡顿!
  4. \n
  5. 运行ftrace(遵循Julia Evan 精彩的解释博客)来获取踪迹,看看它kswapd0往往会卡在shrink_slabsuper_cache_count、 和中list_lru_count_one
  6. \n
  7. 谷歌一下shrink_slab lru slow,找到补丁集!
  8. \n
  9. 切换到 Linux 4.19-rc3 并验证问题是否已修复。
  10. \n
\n