解决方案:改用BFQ调度器

解决方案:改用BFQ调度器

我以前从未遇到过这种情况,但大多数时候我都会小心地nice ionice -c3在要执行的命令前面加上一个。但这次使用niceionice只是延迟了效果。

不管怎样,我使用 Ubuntu 20.04 作为我的主要系统,即台式机。它已完全修补并保持最新,运行 5.4 内核(即没有其他可用内核)。我用 Cinnamon 运行它(是的,它是真正的 Ubuntu,而不是 Mint 之类的),但上次重新安装系统时必须通过服务器 ISO 安装,因为没有一个桌面 ISO 成功启动。我提到这一点是因为我不确定这是否在某种程度上起作用。

当我开始7z压缩一个几十 GiB 大小的文件时,系统变得完全没有响应。无法切换到文本控制台,无法通过 SSH 连接,鼠标光标无法移动……

从这种情况中恢复的唯一方法是关闭系统电源再打开(在我的情况下,我长按电源键)。

发生这种情况后,我阅读了一些有关 Linux 调度程序(我并没有主动修改它)的内容,并了解到 CFS(完全公平调度程序)自某些版本以来一直是默认调度程序。但是,很明显,它让所有其他进程都处于饥饿状态,而让一个以 nice 开头的程序运行ionice -c3……这似乎一点也不公平。

systemd 日志只显示文件系统驱动程序无法为托管正在同时运行的 VM 的进程写入的迹象。

我怎样才能进一步诊断这个问题并最终解决这个问题,以便我打算用作桌面不会变得完全没有反应吗?

注意:我宁愿 OOM 杀手介入并消灭某些进程,也不愿系统完全失去响应。但据我所知,OOM 杀手并不介意。


系统有 64 GiB 的 RAM,没有活动的交换文件(我可以忍受由于内存不足而导致程序失败的少数情况)

# sysctl -A | grep -v _domain | grep '\.sched'
kernel.sched_autogroup_enabled = 1
kernel.sched_cfs_bandwidth_slice_us = 5000
kernel.sched_child_runs_first = 0
kernel.sched_itmt_enabled = 1
kernel.sched_latency_ns = 24000000
kernel.sched_migration_cost_ns = 500000
kernel.sched_min_granularity_ns = 3000000
kernel.sched_nr_migrate = 32
kernel.sched_rr_timeslice_ms = 100
kernel.sched_rt_period_us = 1000000
kernel.sched_rt_runtime_us = 950000
kernel.sched_schedstats = 0
kernel.sched_tunable_scaling = 1
kernel.sched_util_clamp_max = 1024
kernel.sched_util_clamp_min = 1024
kernel.sched_wakeup_granularity_ns = 4000000

... 和(UUID 已删除)...

# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-5.4.0-73-generic root=UUID=xxx ro quiet loglevel=3 vga=current nosplash udev.log_priority=3 rd.systemd.show_status=auto rd.udev.log_priority=3 plymouth.enable=0

(后者表明我没有告诉它使用不同的调度程序)

总体配置如下(略有删减):

# inxi -b -C -G -m
System:    Host: XXX Kernel: 5.4.0-73-generic x86_64 bits: 64 Desktop: Cinnamon 4.4.8
           Distro: Ubuntu 20.04.2 LTS (Focal Fossa)
Machine:   Type: Desktop System: Dell product: Precision 5820 Tower X-Series v: N/A serial: XXX
           Mobo: Dell model: 02M8NY v: A01 serial: /XXX/XXX/ UEFI: Dell v: 2.8.0 date: 01/15/2021
Memory:    RAM: total: 62.52 GiB used: 3.56 GiB (5.7%)
           Array-1: capacity: 3 TiB note: check slots: 8 EC: None
           Device-1: DIMM3 size: 16 GiB speed: 2666 MT/s
           Device-2: DIMM7 size: No Module Installed
           Device-3: DIMM1 size: 16 GiB speed: 2666 MT/s
           Device-4: DIMM5 size: No Module Installed
           Device-5: DIMM4 size: 16 GiB speed: 2666 MT/s
           Device-6: DIMM8 size: No Module Installed
           Device-7: DIMM2 size: 16 GiB speed: 2666 MT/s
           Device-8: DIMM6 size: No Module Installed
CPU:       Topology: 10-Core model: Intel Core i9-9820X bits: 64 type: MT MCP L2 cache: 16.5 MiB
           Speed: 1200 MHz min/max: 1200/4200 MHz Core speeds (MHz): 1: 1200 2: 1200 3: 1200 4: 1200 5: 1200 6: 1200 7: 1201
           8: 1201 9: 1201 10: 1201 11: 1200 12: 1200 13: 1201 14: 1200 15: 1200 16: 1200 17: 1200 18: 1200 19: 1200 20: 1200
Graphics:  Device-1: Advanced Micro Devices [AMD/ATI] Ellesmere [Radeon Pro WX 7100] driver: amdgpu v: 5.6.20.20.45
           Display: server: X.Org 1.20.9 driver: amdgpu unloaded: modesetting
           resolution: 1920x1080~60Hz, 1920x1080~60Hz, 1920x1080~60Hz
           OpenGL: renderer: AMD Radeon Pro WX 7100 Graphics v: 4.6.14756 Core Profile Context FireGL 20.45

答案1

Ubuntu 20.04 使用内核 5.4(带有 HWE:5.8),其中仅mq-deadline编译了调度程序。

您可以通过查看来检查/sys/block/sda/queue/scheduler。活动调度程序周围有方括号。如果内核中编译了其他调度程序,它们也会显示出来。

例子:

# cat /sys/block/sda/queue/scheduler
[mq-deadline] none

# uname -r
5.4.0-26-generic

调度程序目前mq-deadline不支持使用的机制,请参阅:ionicehttps://unix.stackexchange.com/a/160081/27458

解决方案:改用BFQ调度器

调度bfq程序不需要在内核中编译,而是可以使用内核模块随后加载。

切换到BFQ调度器:

# modprobe  "bfq"
# echo "bfq" > /sys/block/sda/queue/scheduler
# echo "bfq" > /etc/modules-load.d/bfq.conf
# echo 'ACTION=="add|change", KERNEL=="sd*[!0-9]|sr*", ATTR{queue/scheduler}="bfq"' > /etc/udev/rules.d/60-scheduler.rules

查看:

# cat /sys/block/sda/queue/scheduler
mq-deadline [bfq] none

重新启动并再次检查可能也是个好主意。

BFQ 在“虚拟”内核上不可用

如果您使用的是“虚拟”内核,您可能无法使用 bfq内核模块,因为它不包含该linux-modules-extra-5.xxx软件包。

您可以通过切换到“generic-HWE”内核来解决这个问题:

# sudo apt-get install linux-generic-hwe-20.04  linux-tools-generic-hwe-20.04
# reboot

重启后你应该进入 kernel 5.8.0-xxx-generic。你可以检查一下:

# uname -r
5.8.0-59-generic

现在您可以应用上述解决方案。

替代解决方案:Systemd 范围

如果您不想切换 IO 调度程序,则可以使用具有较低 IO 权重的 Systemd 范围。

创建一个文件/usr/local/bin/mh_ionice,内容如下:

#!/bin/bash
if (( EUID == 0 )); then USERMODE=''; else USERMODE='--user'; fi
systemd-run \
  --collect \
  --quiet \
  --scope \
  $USERMODE \
  --nice=19 \
  --property="IOAccounting=yes" \
  --property="IOWeight=1" \
  "$@"

使其可执行:

chmod 755 /usr/local/bin/mh_ionice

现在你可以运行:

mh_ionice  [heavy_command] [arg] [arg] [arg]

答案2

如果系统锁定并且完全没有响应,听起来好像是内存不足了。

在 OOM killer 中启用更积极的选项可能有助于系统恢复,但无助于 7z 完成。

您可以使用 cgroups 来限制 RSS 或使用 ulimit 来限制 7z 可以使用的内存,这可能会防止锁定。仔细调整 cgroups 中的内存参数可能会允许 7z 崩溃,同时为系统其余部分提供良好的性能。

添加交换空间可能会允许其他程序从内存中挤出,从而释放更多内存供 7z 运行。

添加过多的交换空间可能会用抖动代替 OOM 锁定,这只是稍微好一点。减少交换空间可能会让 OOM 终止程序终止作业,而不是抖动。

显然,如果 7z 内存不足,那么添加更多 RAM 将会有很大帮助。

相关内容