A pergunta é quase sempre a mesma: esta noite o site demorava vinte segundos a responder e, de manhã, tudo estava resolvido por si. Já não há nada para ver — o top responde pelo segundo atual, e o que se pergunta é sobre as três da manhã. Segue-se o que significam realmente os números da carga, quais deles têm de ser lidos aos pares e porque é que uma medição isolada engana mais vezes do que ajuda.
Load average: três números e um equívoco frequente
uptime
cat /proc/loadavg
nproc
Os três números são médias de um, cinco e quinze minutos. Não se comparam com zero, mas com o número de núcleos que o nproc indica. Um valor de 8 numa máquina de oito núcleos é carga plena mas saudável: há exatamente tanto trabalho quanto o servidor consegue executar. Um valor de 2 num VPS de um núcleo é uma fila com o dobro do comprimento da capacidade, e cada pedido espera a sua vez.
A relação entre os três números dá a direção. O valor de um minuto bastante acima do de quinze significa que a carga está a subir neste momento. O contrário significa que o pico já passou e o que se vê é a sua cauda.
Agora o equívoco que mais estraga a leitura destes números. No Linux, o load average não é «utilização do processador». Ao contrário de outros sistemas Unix, o Linux conta nele não só os processos que estão a correr ou prontos a correr, mas também os que se encontram no estado D — sono ininterrompível. Isto é, à espera do disco ou de um sistema de ficheiros em rede. Daí o servidor com um load de 12 e o processador quase parado: não se está a trabalhar, está-se numa fila.
Processador ou disco
Separar estes dois casos é a primeira coisa a fazer:
vmstat 1 5
iostat -x 1 3
Na saída do vmstat interessam três colunas. r é quantos processos estão em fila para o processador, b quantos estão bloqueados à espera de entrada/saída e wa a fração de tempo que o processador passou parado à espera do disco. Um wa sustentadamente acima de 10–15 % com us e sy modestos significa que o servidor está limitado pelo disco: acrescentar núcleos não serve de nada, os que existem já estão livres.
Quais os processos que estão à espera pode ser listado nome a nome:
ps -eo state,pid,comm,wchan:30 | awk '$1 ~ /^D/'
Um exemplo da nossa própria prática. Com a configuração de origem, o Suricata escreve cerca de trinta tipos de eventos e não configura qualquer rotação — num servidor em produção isso deu 15 GB de registos em dois dias. A carga não se manifestava como processador ocupado, mas precisamente como I/O wait: o sistema escrevia sem parar e tudo o resto ficava na fila atrás dele. A solução não é um plano maior, mas uma lista de eventos mais curta e uma rotação configurada.
O caso inverso, puramente de processador e bastante menos evidente. Uma página web chamava o apt com o utilizador sob o qual corre o PHP-FPM. O root mantém uma cache binária em /var/cache/apt/pkgcache.bin — 70 MB num anfitrião com uma dúzia de repositórios — e mapeia-a em memória sem custo. Um utilizador comum não pode escrever nesse diretório e reconstrói a cache a cada chamada. Medido na mesma máquina: 0,01 segundos de tempo de processador como root contra 4,2 segundos como utilizador sem privilégios. O mesmo comando, uma diferença de quatrocentas vezes, multiplicada por cada abertura da página.
A conclusão dos dois casos é a mesma: a carga mede-se, não se adivinha. Cronometrar separadamente cada comando suspeito leva meia hora e costuma apontar para outro lado que não aquele de onde partiu a suspeita.
Memória: o free não mostra o que parece
free -h
A coluna used, por si só, diz muito pouco, e a coluna free é francamente enganadora: o Linux entrega a memória não utilizada à cache de páginas e devolve-a às aplicações ao primeiro pedido. A coluna a ler é available — quanto se pode ocupar sem ir para swap. Um buff/cache grande não é um problema, mas o sinal de um sistema a funcionar como deve.
No swap, o que conta não é o valor atual mas a forma. Subiu e voltou a zero: houve um pico curto. Subiu uma vez e ali ficou: o pico já aconteceu, páginas foram expulsas e ninguém as traz de volta — o servidor parece calmo embora, a certa altura, lhe tenha faltado memória. Se a troca está a acontecer neste momento, dizem-no as colunas si e so do vmstat; valores diferentes de zero aí são a forma de lentidão que os utilizadores mais notam.
Se durante a quebra noturna um processo simplesmente desapareceu, a explicação está normalmente aqui:
journalctl -k --since yesterday | grep -i "out of memory"
dmesg -T | grep -i "killed process"
Uma linha como Out of memory: Killed process 1234 (mysqld) resolve a questão melhor do que qualquer gráfico: a base de dados não «caiu sozinha», foi o núcleo que a parou porque a memória acabou.
Quem está a causar isto
ps aux --sort=-%cpu | head -10
ps aux --sort=-%mem | head -10
Uma ressalva: o %CPU do ps é uma média de toda a vida do processo, pelo que um pico curto perde-se nessa lista. Para esse são precisos o top ou o pidstat 1 5, que medem por intervalo.
Quando a carga passa a ser uma questão de segurança
Uns 100 % de processador constantes durante a noite, com um processo de nome sem significado e diretório de trabalho em /tmp ou /dev/shm, é a imagem clássica de um minerador e não a de um site que cresceu. Um pico de tráfego de entrada acompanhado de mais escritas nos registos é um ataque a palavras-passe em curso. Um volume de registos que salta de repente é, em regra, uma tempestade de falsos positivos de um filtro.
As próprias ferramentas de proteção são uma categoria à parte. Num dos nossos servidores o load mantinha-se à volta de três sem um único visitante, e no topo do ps por tempo de processador acumulado não estavam nem o site nem a base de dados, mas o CrowdSec, o fail2ban, o Falco e o Suricata. Não é uma avaria nem um motivo para os desligar, mas o preço da proteção convém conhecê-lo em números: num VPS pequeno, nota-se.
Para que serve observar
Tudo o que ficou dito responde à pergunta «o que está a acontecer agora». A pergunta da manhã — o que aconteceu às três da madrugada — não é coberta por estes comandos: da noite passada não há dados se ninguém os registou. E montar o Prometheus e o Grafana para um único VPS é discutível, porque a pilha que observa acaba por pesar mais do que o servidor observado.
Basta uma linha numa base de dados a cada cinco minutos e uma página que desenhe a partir dela as últimas 24 horas: load average, utilização do processador e I/O wait em separado, memória e swap, leituras e escritas de disco, ocupação da partição, inodes, descritores de ficheiros, ligações. Num único eixo de tempo, os pares leem-se a olho: wa alto com o processador tranquilo, swap que nunca voltou a zero, descritores a aproximarem-se do limite — o futuro erro too many open files torna-se visível horas antes de acontecer. O aspeto disto tudo reunido está na página de demonstração abaixo.