Você comprou um servidor dedicado de última geração, processadores de alta frequência e discos NVMe em RAID 10, mas o PostgreSQL continua lento? A frustração é comum: a maioria dos DBAs foca obsessivamente em configurações do banco de dados (como shared_buffers ou work_mem) e esquece que o sistema operacional atua como um gargalo invisível. O kernel do Linux, configurado com valores padrão genéricos, muitas vezes prioriza a estabilidade sobre a latência, introduzindo atrasos significativos na escrita de dados que podem destruir a performance de transações em tempo real.
Este ajuste fino, conhecido como tuning kernel para alta performance, não é mágica; é engenharia de sistemas aplicada. Ao alinhar o comportamento do kernel com as necessidades específicas do PostgreSQL, você elimina gargalos de sincronização de disco e garante que a memória RAM seja utilizada como um cache eficiente, e não como uma lixeira temporária.
Por que o Linux padrão é lento para bancos de dados?
O Linux foi projetado originalmente para ser um sistema operacional versátil, capaz de rodar desde servidores web até estações de trabalho interativas. Para manter essa generalidade, os valores de tunelamento (sysctl) vêm com configurações conservadoras. O objetivo principal desses valores padrão é evitar que o sistema trave se uma aplicação consumir toda a memória ou inundar o disco com escritas desordenadas.
No entanto, bancos de dados relacionais como o PostgreSQL operam sob um paradigma diferente. Eles exigem previsibilidade, baixa latência e controle rigoroso sobre quando os dados são escritos fisicamente no disco. Quando o kernel decide "ajudar" flushing dados sujos (dirty pages) da memória para o disco de forma agressiva ou desordenada, ele introduz picos de latência que podem ser percebidos pelo banco de dados como timeouts ou travamentos.
Além disso, a gestão de memória padrão pode levar o sistema a trocar páginas de memória para o disco (swap) em momentos críticos, mesmo quando há RAM livre disponível. Isso acontece porque o kernel tenta manter uma certa quantidade de memória livre para alocações urgentes do próprio sistema, uma estratégia que não se aplica bem a bancos de dados que querem usar quase toda a RAM disponível para caches.
Otimizando o VFS Cache Pressure
O primeiro ponto de ajuste crítico é o vfs_cache_pressure. Este parâmetro controla a taxa na qual o kernel recupera memória usada para armazenar informações de cache do sistema de arquivos (como inodes e dentries), em comparação com a memória usada para caches de página.
Pense no cache VFS como o "índice" do seu banco de dados no nível do sistema operacional. Ele mantém o mapeamento de nomes de arquivos e metadados. Se o kernel liberar esse cache muito rapidamente para fazer espaço para outras coisas, o PostgreSQL terá que reconstruir essas estruturas de metadados frequentemente, o que é custoso.
Recomendação: Para a maioria dos servidores de banco de dados, aumentar esse valor faz com que o kernel retenha os metadados por mais tempo.
- Valor padrão: 100
- Valor recomendado: Entre 200 e 500 (dependendo da carga de leitura)
O comando para aplicar essa mudança é:
sysctl -w vm.vfs_cache_pressure=200
Para tornar a alteração persistente, adicione a linha vm.vfs_cache_pressure=200 ao arquivo /etc/sysctl.conf. Lembre-se de que esse ajuste é mais crítico em bancos de dados com muitas tabelas pequenas ou esquemas complexos, onde o overhead de metadados é significativo.
O Grande Vilão: vm.dirty_background_ratio e vm.dirty_ratio
Se houver apenas um parágrafo que você deve memorizar ao fazer tuning de kernel para alta performance no PostgreSQL, é este: o gerenciamento de escritas sujas (dirty pages). O PostgreSQL usa o sistema de arquivos do Linux para persistir dados. Quando você executa um INSERT ou UPDATE, os dados vão primeiro para a memória RAM.
O kernel então precisa escrever esses dados no disco físico. Ele não faz isso imediatamente para cada byte escrito (o que seria terrivelmente lento), mas agrupa as escritas. A questão é: quando o kernel decide que é hora de enviar esses dados para o disco?
Aqui entram dois parâmetros vitais:
- vm.dirty_background_ratio: Define a porcentagem da memória total na qual o kernel começará a escrever páginas sujas para o disco em segundo plano. Ou seja, ele começa a liberar memória "suja" silenciosamente.
- vm.dirty_ratio: Define a porcentagem máxima da memória total que um processo individual pode preencher com dados sujos antes de ser forçado a esperar enquanto o kernel escreve esses dados no disco. Este é o gatilho que causa latência alta para o banco de dados.
No modo padrão, se o vm.dirty_ratio estiver alto (ex: 20%), uma transação massiva pode preencher 20% da RAM com dados não escritos. Quando esse limite é atingido, o processo do PostgreSQL trava até que o disco termine de gravar tudo. Isso cria picos de latência imprevisíveis.
Estratégia de Tuning: Reduza esses valores para forçar o kernel a escrever no disco de forma mais constante e em lotes menores, evitando que o banco de dados espere por grandes blocos de escrita.
- vm.dirty_background_ratio: Reduza para 1% ou 2%. Isso garante que o cache seja limpo continuamente.
- vm.dirty_ratio: Reduza para 5% ou 10%. Isso limita a quantidade máxima de dados sujos que um processo pode acumular antes de ser bloqueado.
Comandos de aplicação:
sysctl -w vm.dirty_background_ratio=1
sysctl -w vm.dirty_ratio=5
Isso não significa que você deve escrever no disco a cada milissegundo. O PostgreSQL já possui seu próprio mecanismo de escrita (WAL - Write Ahead Log) e checkpointing. Ao reduzir esses valores do kernel, você apenas impede que o sistema operacional se torne o gargalo principal, permitindo que o PostgreSQL gerencie o fluxo de dados de forma mais suave.
Escolhendo o Scheduler de I/O Correto
O escalonador de E/S (I/O Scheduler) é o responsável por decidir a ordem em que as requisições de leitura e escrita são enviadas ao disco. Em discos mecânicos (HDD), o objetivo era minimizar o movimento físico da cabeça de leitura (seek time). Em SSDs e NVMe, não há partes móveis, então as estratégias antigas podem na verdade degradar a performance.
Historicamente, usávamos CFQ (Complete Fairness Queuing) para equilibrar a largura de banda entre processos. Hoje, com o advento dos discos rápidos, outras opções surgiram.
| Scheduler | Ideal Para | Impacto no PostgreSQL |
|---|---|---|
| CFQ | HDDs antigos, sistemas com muitos usuários | Alta latência, overhead desnecessário em SSDs. |
| BFQ | Sistemas interativos, desktops | Muito conservador, pode limitar throughput em bancos de dados. |
| Deadline | Bancos de dados, workloads com baixa latência crítica | Garante que requisições não fiquem presas na fila. Excelente para PostgreSQL. |
| Noop / NVM | SSDs NVMe, discos em rede (iSCSI/NFS) | Fila simples FIFO. Deslocamento da lógica para o driver ou hardware. |
Para a maioria dos cenários modernos de banco de dados, especialmente com SSDs SATA/SAS, o scheduler Deadline é frequentemente considerado o melhor equilíbrio entre latência e throughput. Ele garante que nenhuma requisição fique "estagnada" na fila por muito tempo.
Para NVMe puro, o none (ou noop em kernels mais antigos) pode ser mais eficiente, pois o hardware já gerencia a fila de comandos internamente. Verifique seu dispositivo com:
cat /sys/block/sda/queue/scheduler
Para alterar permanentemente, você precisará configurar o GRUB ou usar um script de init, dependendo da sua distribuição Linux.
Swappiness e Gerenciamento de Memória
O parâmetro vm.swappiness controla a tendência do kernel para trocar páginas de memória não usadas para o disco (swap). O valor varia de 0 a 100.
Mito comum: "Defina swappiness como 0 para nunca usar swap."
Realidade técnica: Embora definir como 0 pareça seguro, o kernel Linux ainda pode ser forçado a trocar memória se ficar completamente sem RAM livre e não conseguir liberar buffers de disco. Isso pode causar um "thrashing" catastrófico onde o sistema trava completamente.
No entanto, para bancos de dados, queremos evitar que o kernel troque páginas ativas do banco de dados (que estão sendo usadas) para o disco. O valor padrão (geralmente 60) é muito alto para um servidor dedicado a banco de dados.
Recomendação:
- Defina
vm.swappinessentre 1 e 10. - Isso diz ao kernel: "Prefira liberar cache de disco (que pode ser lido novamente do disco rapidamente) em vez de trocar páginas ativas da aplicação".
Além disso, considere ajustar o vm.overcommit_memory. O PostgreSQL gerencia sua própria alocação de memória. Configurar vm.overcommit_memory=1 diz ao kernel para sempre aprovar solicitações de alocação de memória, o que pode ser útil para evitar erros de "Out of Memory" durante picos de operação, desde que você tenha RAM física suficiente.
Perguntas frequentes
1. Preciso reiniciar o servidor após alterar o sysctl?
Não necessariamente. Você pode aplicar as mudanças em tempo real usando o comando sysctl -w parametro=valor ou sysctl -p para carregar todas as configurações do arquivo de configuração. No entanto, algumas alterações, especialmente aquelas relacionadas ao I/O scheduler ou núcleos específicos, podem exigir uma reinicialização para serem aplicadas corretamente a todos os dispositivos.
2. Essas configurações de tuning kernel para alta performance funcionam para MySQL e MongoDB também?
Sim, na maioria dos casos. Bancos de dados relacionais e NoSQL compartilham a mesma infraestrutura subjacente do Linux. As otimizações de vm.dirty_ratio e swappiness são benéficas para qualquer banco de dados que faça escritas intensivas no disco. O ajuste de vfs_cache_pressure pode variar dependendo de quão agressivo o banco é na leitura de metadados.
3. Posso usar essas configurações em produção sem testar?
Nunca aplique mudanças de kernel em produção sem teste prévio. Cada carga de trabalho é única. O que funciona para um OLTP (Online Transaction Processing) pode não ser ideal para um OLAP (Analytics). Teste em um ambiente de staging que espelhe a produção e monitore as métricas de latência e throughput antes de propagar.
4. O PostgreSQL já não otimiza isso internamente?
O PostgreSQL é excelente em gerenciar sua própria memória interna (shared buffers, wal_buffers), mas ele não tem controle direto sobre como o kernel do Linux gerencia a memória física e as escritas no disco. O banco de dados envia comandos ao sistema operacional e espera que o OS os execute da forma mais eficiente possível. Se o OS estiver configurado para ser "preguiçoso" ou "caótico", o PostgreSQL sofrerá.
5. Como saber se o tuning está funcionando?
Use ferramentas como iostat -x 1 para observar a utilização do disco e latência de E/S, e vmstat 1 para monitorar atividade de swap e interrupções. Se você ver picos de latência de disco sincronizados com escritas do banco, ou se o valor de si/so (swap in/out) no vmstat for diferente de zero, ainda há trabalho a fazer.
Conclusão
O tuning de kernel para alta performance não é sobre tornar o servidor "mais rápido" em termos brutos de CPU, mas sobre tornar o sistema mais previsível e reduzir a variabilidade da latência. Ao ajustar parâmetros como vm.dirty_ratio, vfs_cache_pressure e o scheduler de I/O, você alinha o comportamento do Linux com as expectativas do PostgreSQL.
Lembre-se: otimização é um processo iterativo. Comece pelos ajustes de memória e escrita, monitore os resultados e ajuste finamente conforme a carga de trabalho evolui. Um banco de dados bem tunado no nível do kernel reduz a necessidade de hardware excessivo, permitindo que você extraia o máximo potencial do seu investimento em infraestrutura.
Se você busca garantir que sua infraestrutura esteja pronta para lidar com picos de demanda sem gargalos invisíveis, contar com especialistas em administração de sistemas é fundamental. Na Toda Solução, oferecemos suporte especializado em infraestrutura e cloud para manter seu banco de dados rodando com a eficiência máxima, permitindo que você foque no que realmente importa: o crescimento do seu negócio.