Evita que um script escape de recursos do sistema e deixe de funcionar por todo o sistema

6

Eu estava pensando se há uma maneira "canônica" de ter isso?

Antecedentes e & descrição

Eu tenho que instalar algum programa no servidor live. Embora eu confie no fornecedor (FOSS, Github, vários autores ...) eu preferiria evitar evitar um cenário totalmente impossível de script caindo em alguns problemas e esgotando os recursos do sistema e deixando o servidor sem resposta. Eu tive o caso de instalar o amavis que foi iniciado logo depois e por causa de alguma configuração confusa, ele produziu loadavg de > 4 e o sistema mal responde.

Meu primeiro ensinamento foi nice - nice -n 19 thatscript.sh . Isso pode e não pode ajudar, mas eu estava pensando que seria melhor que eu escrevesse e ativasse o script que faria o seguinte:

  • executado como daemon, em (exemplo) 500ms-2s

  • verifique o processo marcado com ps e grep

  • se processo (s) rotulado (s) (ou qualquer outro processo) precisar de muita CPU (ainda a ser definida) - mate-os com SIGKILL

Meu segundo ensinamento foi - não seria a primeira vez que eu estava reinventando a roda.

Então, existe alguma boa maneira de "prender" o programa e os processos produzidos por ele em alguma quantidade limitada predefinida de recursos do sistema ou de morte automatizada se algum limite for atingido por eles?

    
por Miloš Đakonović 19.06.2017 / 15:29

2 respostas

5

Alternativa # 1: monitore seu processo com monit

Instale M / Monit e crie um arquivo de configuração baseado neste modelo:

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

Alternativa # 2: Limite o uso da CPU do processo com cgroups

A solução mais nativa do Linux para todos eles. Oferece muitas opções e complexidade.

Exemplo:

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

Encorajo-o a ler mais em:

DigitalOcean - How-to: Limite de recursos usando cgroups no CentOS 6

RedHat - Guia de gerenciamento de recursos

Oracle - Lista de subsistemas de cgroups

Alternativa # 3: Limite o uso da CPU do processo com cpulimit

Obtenha a versão mais recente do cpulimit do seu gerenciador de pacotes de sua preferência, ou obtenha a fonte disponível em GitHub .

Limite o uso da CPU para 90%: cpulimit -l 90 /usr/bin/myprogram > /dev/null &

Sidenote:

Você também pode fixar um certo processo para usar certos núcleos de CPU para garantir que você sempre tenha algum poder de CPU livre.

    
por 21.06.2017 / 19:43
5

systemd pode limitar os recursos de um alvo / serviço. Na página man :

CPUQuota :

Assign the specified CPU time quota to the processes executed. Takes a percentage value, suffixed with "%". The percentage specifies how much CPU time the unit shall get at maximum, relative to the total CPU time available on one CPU. Use values > 100% for allotting CPU time on more than one CPU. This controls the "cpu.max" attribute on the unified control group hierarchy and "cpu.cfs_quota_us" on legacy. For details about these control group attributes, see cgroup-v2.txt and sched-design-CFS.txt.

Example: CPUQuota=20% ensures that the executed processes will never get more than 20% CPU time on one CPU.

Implies "CPUAccounting=true".

Como o uso disso implica CPUAccounting , incluirei também

CPUAccounting :

Turn on CPU usage accounting for this unit. Takes a boolean argument. Note that turning on CPU accounting for one unit will also implicitly turn it on for all units contained in the same slice and for all its parent slices and the units contained therein. The system default for this setting may be controlled with DefaultCPUAccounting= in systemd-system.conf(5).

Também citarei Slice :

The name of the slice unit to place the unit in. Defaults to system.slice for all non-instantiated units of all unit types (except for slice units themselves see below). Instance units are by default placed in a subslice of system.slice that is named after the template name.

Então, por padrão, tudo será lançado no mesmo slice , o que significa tudo em um único pool de recursos.

Há também MemoryHigh para analisar:

MemoryHigh :

Specify the high limit on memory usage of the executed processes in this unit. Memory usage may go above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away aggressively in such cases. This is the main mechanism to control memory usage of a unit.

Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a percentage value may be specified, which is taken relative to the installed physical memory on the system. If assigned the special value "infinity", no memory limit is applied. This controls the "memory.high" control group attribute. For details about this control group attribute, see cgroup-v2.txt.

Implies "MemoryAccounting=true".

This setting is supported only if the unified control group hierarchy is used and disables MemoryLimit=.

Você pode facilmente lançar um script em um serviço systemd .

Assumindo que /usr/local/thatscript.sh é o script:

/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

Em seguida, você precisará de systemctl daemon-reload para ler o novo arquivo de serviço e, em seguida, você pode systemctl enable thatscript.service se desejar que ele seja executado na inicialização ou systemctl start thatscript.service , se desejar iniciá-lo manualmente.

    
por 22.06.2017 / 13:11