- Qual é a maneira mais rápida de recuperar o controle de um sistema Linux que não responde ou é extremamente lento devido à troca excessiva?
Já respondeu acima com Alt-SysRq-F
- Existe uma maneira eficaz de impedir que essa troca ocorra em primeiro lugar, por exemplo, limitando a quantidade de memória que um processo pode tentar alocar?
Estou respondendo a esta 2ª 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ê desejar um seguro extra
Além disso, como mencionado brevemente:
Você pode usar o CGroups para limitar o uso de recursos e evitar esses problemas
De fato, o cgroups oferece controle mais avançado, mas atualmente é mais complicado de configurar na minha opinião.
Ulimit da velha escola
Uma vez desligado
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)
Isto:
- Define um limite flexível de 1 GB de uso geral de memória (ulimit assume limite na unidade de kB)
- Executa uma chamada de função bash recursiva
r2(){ r2 $@$@;};r2 r2
que exponencialmente consumirá CPU e RAM, dobrando-se infinitamente enquanto solicita memória da pilha.
Como você pode ver, ele foi interrompido ao tentar solicitar mais de 1 GB.
Observe que -v
opera na alocação de memória virtual (total, ou seja, físico + swap).
Protecçã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 comportamento inadequado:
- Defina um limite de espaço de endereço físico para todos os processos.
address space limit = <physical memory> - 256MB
.
- Portanto, nenhum processo único com uso de memória ganancioso ou um loop ativo e vazamento de memória pode consumir TODA a memória física.
- Há 256 MB de espaço livre 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:
- Atenua apenas um único processo que exagere no uso de memória.
- Não impedirá que uma carga de trabalho de vários processos com alta pressão de memória cause batidas (o cgroups é a resposta).
- Não use a
rss
opção em limits.conf. Não é respeitado pelos kernels mais recentes.
- É conservador.
- Em teoria, um processo pode solicitar especulativamente muita memória, mas apenas usar ativamente um subconjunto (menor conjunto de trabalho / uso de memória residente).
- O limite rígido acima fará com que esses processos sejam interrompidos (mesmo que, caso contrário, eles tenham sido executados corretamente, pois o Linux permite que o espaço de endereço da memória virtual seja supercomprometido).
Grupos CG mais recentes
Oferece mais controle, mas atualmente é mais complexo de usar:
- Melhora na 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!
- Necessidade de permitir algumas bandeiras do kernel cgroup em bootloader:
cgroup_enable=memory swapaccount=1
.
- Isso não aconteceu por padrão no Ubuntu 16.04.
- Provavelmente devido a algumas implicações no desempenho de despesas extras de contabilidade.
- O material do cgroup / systemd é relativamente novo e está mudando bastante, então o fluxo upstream implica que os distribuidores de distribuição do Linux ainda não tornaram fácil o uso. 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 de usuário oficialmente suportada.
- os arquivos de unidade systemd ainda não parecem ter nenhum padrão "vendor / distro" predefinido 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, mastigando a RAM como um processo em segundo plano e sendo 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, esperamos ver "distro / vendors" pré-configurar prioridades e limites do cgroup (via unidades systemd) para coisas importantes como SSH e a pilha gráfica, para que eles nunca fiquem com falta de memória.