Administro um site rodando em uma instância t1-micro no
Amazon Web Services (AWS) e na última semana, tenho tido muitos problemas de queda do
MySQL.
Analisando o
syslog, encontrei diversas vezes a mesma informação:
Feb 12 06:27:55 ip-xx.xx.xx.xx kernel: [8495594.190585] Out of memory: Kill process 746 (mysqld) score 143 or sacrifice child
Feb 12 06:27:55 ip-xx.xx.xx.xx kernel: [8495594.190600] Killed process 746 (mysqld) total-vm:886216kB, anon-rss:86132kB, file-rss:0kB
Eu já havia colocado uma linha na
crontab para iniciar o MySQL, caso ele estivesse fora da memória, mas o caso, é que ele continuava caindo e eu não conseguia entender o por quê.
Na verdade, o por quê está claro no syslog:
OOM ou Out Of Memory
Isto significa que, em algum momento, a memória se esgotou e então o sistema ativa um processo para lidar com esta situação.
O kernel do
GNU/Linux utiliza uma implementação chamada "
Optimistic Memory Allocation", que permite que as aplicações solicitem memória e recebam "mais" do que poderia ser ofertado.
O sistema assume (e espera) que todas aplicações rodando não utilizem toda a memória requerida de uma vez. Dessa forma, as aplicações acham que tem disponível uma determinada quantidade de memória, mas na realidade não tem.
Então, quando a memória do sistema chega no seu limite, o
OOM Killer (Out Of Memory Killer) entra em ação. Ele é responsável por lidar com os processos em memória quando não há mais espaço para trabalhar, evitando que todo o sistema fique travado.
O OOM Killer procura por um processo que ele possa liquidar e então executa-o, retirando-o da memória. Ele utiliza um sistema heurístico para escolher quais processos devem ser encerrados e é baseado em um score associado à cada processo, que é calculado pelo oom_badness(), também conhecido como badness(), dentro do kernel.
O algoritmo é relativamente simples e basicamente funciona da seguinte maneira: Quanto mais memória um processo usa, mais pontos ele acumula no seu score.
Outros fatores que ele considera:
- Consumo de memória;
- Ownership do processo;
- Idade do processo;
- CPU time;
- Valor de nice do processo;
- Flags do processo;
- Configuração do "oom_adj/oom_score_adj".
É nessa hora que o MySQL pode se dar mal. Simplesmente porque ele será o processo que consumirá mais memória no seu sistema.
Como resolver esse problema, então?
No meu caso, resolvi adicionando uma partição de SWAP à minha instância. Verifiquei que instâncias no AWS em princípio não possuem uma partição de SWAP, e, em casos onde a instância possui pouca memória, isso pode ser primordial para o bom funcionamento do sistema.
O processo é simples e vou exemplificar como pode ser executado em duas etapas, a primeira no console do AWS e a segunda em um shell para a instância:
1. Abra o Console AWS (
http://console.aws.amazon.com) e vá para: EC2 → Volumes
2. Clique em: "Create Volume". Selecione o tipo (Standard), o tamanho e a zona;
3. Clique com o botão direito em cima do volume e selecione "Attach Volume", para associá-lo à instância que está rodando;
4. Abra um shell para a sua instância:
ssh -i <arq.pem> <usuario>@<IP_da_instancia>
Obs.: Vamos exemplificar utilizando
/dev/xvdf, para o novo volume anexado.
5. Execute o
fdisk:
sudo fdisk /dev/xvdf
E utilize a sequência:
1. n Cria uma nova partição;
2. p Primária;
3. Enter Seleciona o número 1;
4. Enter Seleciona o primeiro setor;
5. Enter Seleciona o último setor;
6. t Para selecionar o tipo de partição;
7. 82 Linux swap;
8. w Salva e sai.
Depois ative a SWAP:
sudo mkswap /dev/xvdf1
$ sudo swapon /dev/xvdf1
Pronto, criamos um novo volume, anexamos à instância rodando, particionamos como SWAP e o ativamos.
Mas existem outras maneiras de resolver o problema, como:
1. Ajustando adequadamente as configurações e buffers do MySQL. Ex.: key_buffer_size, innodb_buffer_pool;
2. Ajustando o OOM score do seu sistema, por exemplo:
# cat /proc/$(pidof mysqld)/oom_score_adj
# echo '-20' > /proc/$(pidof mysqld)/oom_score_adj
# cat /proc/$(pidof mysqld)/oom_score
O range do OOM Score vai de -1000 a 1000 (ou -17 até 15 em sistemas mais antigos). Lembrando que, utilizando o valor mínimo, não desabilita o OOM Score, somente reduz suas chances de ser convidado a se retirar da memória.
Dados adicionais
Informações mais detalhadas podem ser encontradas no artigo (em inglês):
Dados do AWS:
- Amazon AWS Micro Instance:
- 613 MiB memory
- Up to 2 EC2 Compute Units (for short periodic bursts)
- EBS storage only
- 32-bit or 64-bit platform
- I/O Performance: Low
- EBS-Optimized Available: No
- API name: t1.micro