防止脚本耗尽系统资源并导致整个系统崩溃

防止脚本耗尽系统资源并导致整个系统崩溃

我在想是否有“规范”的方式来做到这一点?

背景及描述

我必须在实时服务器上安装一些程序。尽管我确实信任供应商(FOSS、Github、多个作者......),但我宁愿确保避免脚本陷入某些麻烦并耗尽系统资源并导致服务器无响应的并非完全不可能的情况。我遇到过安装 amavis 的情况,它是在安装之后立即启动的,由于一些混乱的配置,它产生了 >4 的 loadavg,并且系统几乎没有响应。

我的第一个教学是nice- nice -n 19 thatscript.sh。这可能有帮助,也可能没有帮助,但我认为最好编写并激活执行以下操作的脚本:

  • 作为守护进程运行,(示例)500ms-2s

  • 检查带有ps和标记的过程grep

  • 如果标记的进程(或任何其他进程)占用太多 CPU(尚未定义) - 杀死它们SIGKILL

我的第二个教训是——这不是我第一次重新发明轮子。

那么,有没有什么好方法可以将程序及其生成的进程“监禁”到一些预定义的有限数量的系统资源中,或者在达到某个阈值时自动终止?

答案1

替代方案#1:使用 monit 监控进程

安装中号/监控并基于此模板创建配置文件:

check process myprogram
matching "myprogram.*"
start program = "/usr/bin/myprogram" with timeout 10 seconds
stop program = "/usr/bin/pkill thatscript"
if cpu > 99% for 2 cycles then stop
if loadavg (5min) > 80 for 10 cycles then stop

替代方案#2:使用 cgroup 限制进程 CPU 使用

其中最原生的 Linux 特定解决方案。提供了很多选择和复杂性。

例子:

sudo cgcreate -g cpu:/cpulimited
sudo cgset -r cpu.shares=512 cpulimited
sudo cgexec -g cpu:cpulimited /usr/bin/myprogram > /dev/null &

我鼓励您阅读更多内容:

DigitalOcean - 操作方法:在 CentOS 6 上使用 cgroup 限制资源

RedHat - 资源管理指南

Oracle - cgroups 子系统列表

替代方案#3:使用 cpulimit 限制进程 CPU 使用

从您选择的包管理器获取最新版本的 cpulimit,或者通过获取可用源GitHub

将 CPU 使用率限制为 90%:cpulimit -l 90 /usr/bin/myprogram > /dev/null &

边注:

您还可以固定某个进程来使用某些 CPU 核心,以确保您始终拥有一些空闲的 CPU 能力。

答案2

systemd可以限制目标/服务的资源。从man页面:

CPUQuota

将指定的CPU时间配额分配给执行的进程。取百分比值,后缀为“%”。该百分比指定相对于一个 CPU 上可用的总 CPU 时间,该单元最多可以获得多少 CPU 时间。使用 > 100% 的值在多个 CPU 上分配 CPU 时间。这控制cpu.max统一控制组层次结构上的“ ”属性和cpu.cfs_quota_us旧版上的“ ”属性。有关这些控制组属性的详细信息,请参阅cgroup-v2.txtsched-design-CFS.txt

示例:CPUQuota=20%确保执行的进程在一个 CPU 上永远不会获得超过 20% 的 CPU 时间。

暗示 ” CPUAccounting=true”。

因为使用这个意味着CPUAccounting我也会包括它

CPUAccounting

打开本机的 CPU 使用率统计。采用布尔参数。请注意,打开一个单元的 CPU 占用也会隐式地为同一切片中包含的所有单元及其所有父切片和其中包含的单元打开它。此设置的系统默认值可以通过DefaultCPUAccounting=in进行控制systemd-system.conf(5)

我也会引用Slice

用于放置单元的切片单元的名称。system.slice对于所有单元类型的所有非实例化单元,默认为(切片单元本身除外,见下文)。默认情况下,实例单元放置在system.slice以模板名称命名的子切片中。

因此,默认情况下,所有内容都会被扔进同一个slice资源池中,这意味着所有内容都在一个资源池中。

还有一些MemoryHigh值得一看的地方:

MemoryHigh

指定该单元中执行的进程的内存使用上限。如果不可避免,内存使用量可能会超过限制,但在这种情况下,进程会严重减慢,并且内存会被大量占用。这是控制单元内存使用的主要机制。

获取内存大小(以字节为单位)。如果该值以 K、M、G 或 T 为后缀,则指定的内存大小将分别解析为千字节、兆字节、千兆字节或太字节(以 1024 为基数)。或者,可以指定相对于系统上安装的物理内存的百分比值。如果指定特殊值“无穷大”,则不应用内存限制。这控制“ memory.high”控制组属性。有关此控制组属性的详细信息,请参阅cgroup-v2.txt

暗示 ” MemoryAccounting=true”。

仅当使用统一控制组层次结构并禁用时才支持此设置MemoryLimit=


您可以轻松地将脚本放入systemd服务中。

假设/usr/local/thatscript.sh脚本是:

/usr/lib/systemd/system/thatscript.service

[Unit]
Description=This runs "thatscript"
ConditionFileNotEmpty=/usr/local/thatscript.sh

[Service]
Type=simple
ExecStart=/usr/local/thatscript.sh
CPUQuota=20%

[Install]
WantedBy=multi-user.target

然后,您需要systemctl daemon-reload读入新的服务文件,systemctl enable thatscript.service如果您希望它在启动时运行,或者systemctl start thatscript.service您想手动启动它,则可以这样做。

相关内容