- What is the quickest way to regain control of a Linux system that has become nonresponsive or extremely sluggish due to excessive swapping?
Já foi respondido acima com Alt-SysRq-F
- Is there an effective way to prevent such swapping from occurring in the first place, for instance by limiting the amount of memory a process is allowed to try to allocate?
Estou respondendo esta segunda parte. Sim, ulimit
ainda funciona bem o suficiente para limitar um único processo. Você pode:
- defina um limite flexível para um processo que você sabe que provavelmente ficará fora de controle
- defina um limite rígido para todos os processos, se você quiser um seguro extra
Além disso, como mencionado brevemente:
You can use CGroups to limit resource usage and prevent such problems
De fato, os cgroups oferecem controle mais avançado, mas atualmente são mais complicados de configurar na minha opinião.
Ulimit da velha escola
Uma vez fora
Aqui está um exemplo simples:
$ bash
$ ulimit -S -v $((1*2**20))
$ r2(){r2 $@$@;};r2 r2
bash: xmalloc: .././subst.c:3550: cannot allocate 134217729 bytes (946343936 bytes allocated)
- Define um limite flexível de 1 GB de uso geral de memória (ulimit pressupõe limite na unidade kB)
- Executa uma chamada de função bash recursiva
r2(){ r2 $@$@;};r2 r2
que extinguirá exponencialmente a CPU e a RAM, duplicando-se infinitamente enquanto solicita a memória da pilha.
Como você pode ver, parou quando tentou solicitar mais de 1GB.
Observe que -v
opera na alocação de memória virtual (total, ou seja, físico + swap).
Proteção permanente
Para limitar a alocação de memória virtual, as
é o equivalente a -v
para limits.conf
.
Eu faço o seguinte para proteger contra qualquer processo de mau comportamento:
- Defina um limite de espaço de endereçamento rígido para todos os processos.
-
address space limit = <physical memory> - 256MB
.
- Portanto, nenhum processo isolado com uso de memória voraz ou um loop ativo e vazamento de memória podem consumir TODA a memória física.
O espaço de - de 256 MB está disponível para processamento essencial com ssh ou console.
Um forro:
$ sudo bash -c "echo -e \"*\thard\tas\t$(($(grep -E 'MemTotal' /proc/meminfo | grep -oP '(?<=\s)\d+(?=\skB$)') - 256*2**10))\" > /etc/security/limits.d/mem.conf"
Para validar, isso resulta no seguinte (por exemplo, no sistema de 16 GB):
$ cat /etc/security/limits.d/mem.conf
* hard as 16135196
$ ulimit -H -v
161351960
Notas:
- Apenas atenua um único processo que vai ao mar com o uso da memória.
- Não impede uma carga de trabalho de vários processos com muita pressão na memória, causando a debulha (o cgroups é a resposta).
- Não use a opção
rss
no limits.conf. Não é respeitado pelos novos kernels.
- É conservador.
- Em teoria, um processo pode solicitar especulativamente muita memória, mas somente usar ativamente um subconjunto (menor uso de conjunto de memória / residente de trabalho).
- O limite máximo acima fará com que tais processos sejam abortados (mesmo que possam ter sido executados corretamente, caso o Linux permita que o espaço de endereço da memória virtual seja supercomprometido).
CGroups mais recentes
Oferece mais controle, mas atualmente é mais complexo de usar:
- Aprimora a oferta ulimit.
-
memory.max_usage_in_bytes
pode contabilizar e limitar a memória física separadamente.
- Considerando que
ulimit -m
e / ou rss
in limits.conf
foi criado para oferecer funcionalidade semelhante, mas isso não funciona desde o kernel Linux 2.4.30!
- É necessário ativar alguns sinalizadores de cgroup do kernel no carregador de inicialização:
cgroup_enable=memory swapaccount=1
.
- Isso não aconteceu por padrão com o Ubuntu 16.04.
- Provavelmente devido a algumas implicações de desempenho da sobrecarga extra de contabilidade.
- O material do cgroup / systemd é relativamente novo e está mudando um pouco, então o fluxo do fluxo de dados implica que os distribuidores de Linux ainda não o tornaram fácil de usar. Entre 14.04LTS e 16.04LTS, as ferramentas de espaço do usuário para usar cgroups foram alteradas.
-
cgm
agora parece ser a ferramenta de espaço do usuário oficialmente suportada.
Os arquivos da unidade - systemd ainda não parecem ter nenhum padrão "vendor / distro" pré-definido para priorizar serviços importantes como o ssh.
Por exemplo para verificar as configurações atuais:
$ echo $(($(cat /sys/fs/cgroup/memory/memory.max_usage_in_bytes) / 2**20)) MB
11389 MB
$ cat /sys/fs/cgroup/memory/memory.stat
...
Por exemplo para limitar a memória de um único processo:
$ cgm create memory mem_1G
$ cgm setvalue memory mem_1G memory.limit_in_bytes $((1*2**30))
$ cgm setvalue memory mem_1G memory.memsw.limit_in_bytes $((1*2**30))
$ bash
$ cgm movepid memory mem_1G $$
$ r2(){ r2 $@$@;};r2 r2
Killed
Para vê-lo em ação, chewing RAM como um processo em segundo plano e, em seguida, ser morto:
$ bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2' & while [ -e /proc/$! ]; do ps -p $! -o pcpu,pmem,rss h; sleep 1; done
[1] 3201
0.0 0.0 2876
102 0.2 44056
103 0.5 85024
103 1.0 166944
...
98.9 5.6 920552
99.1 4.3 718196
[1]+ Killed bash -c 'cgm movepid memory mem_1G $$; r2(){ r2 $@$@;};r2 r2'
Observe o crescimento exponencial (potência de 2) nas solicitações de memória.
No futuro, vamos esperar ver "distro / vendors" pré-configurar prioridades e limites do cgroup (via unidades systemd) para coisas importantes como SSH e a pilha gráfica, de tal forma que elas nunca fiquem famintas de memória.