...

Rácio «Dirty» do Linux e rácio «Dirty Background»: ajustes finos para um desempenho de gravação ideal

Eu mostro como linux sujo e a relação de fundo sujo (dirty background ratio) controlam a cache da página, influenciando assim o débito de escrita, a latência e a segurança dos dados. Desta forma, podes definir valores-limite concretos que ativam os flusher em tempo útil, evitam bloqueios e aumentam o desempenho de escrita das tuas cargas de trabalho.

Pontos centrais

Para começar, vou resumir brevemente as ideias principais, antes de aprofundar o assunto.

  • Páginas obscenas armazena os Writes na RAM e agrupa muitos pequenos acessos em operações de E/S mais eficientes.
  • rácio_de_fundo_sujo inicia threads do Flusher em segundo plano, limitando assim, de forma imperceptível, a quantidade de resíduos.
  • rácio de sujidade limita os processos de gravação quando o limite máximo é ultrapassado.
  • Relação Ambos os valores determinam os picos de latência, o débito e o tamanho do buffer.
  • Variantes de bytes (dirty_bytes) proporcionam um controlo mais preciso e absoluto em servidores de grande dimensão.

Compreender as «Dirty Pages»

Quando um processo grava dados, estes vão primeiro para o Cache de página e são marcados como „dirty“ até que o kernel consiga gravá-los no disco. Este armazenamento em buffer acelera as aplicações, porque a RAM reage mais rapidamente do que qualquer SSD ou HDD e as pequenas gravações acabam por se agrupar em grandes transferências sequenciais. Tenho sempre em mente a quantidade de „sujidade“ que permito, pois um buffer excessivo pode prolongar as filas de espera ou, em caso de falhas, colocar em risco mais dados não guardados. Quem compreende o funcionamento toma melhores decisões em relação ao writeback, à latência e à pressão de memória. Um breve artigo de contextualização sobre o Cache de reescrever ajuda a compreender bem este mecanismo.

Segurança de dados, fsync e janela de falha

Os valores-limite não influenciam apenas o desempenho, mas também a tua janela de risco. Faço uma estimativa com uma regra prática simples: a quantidade máxima de dados não seguros dividida pela taxa de transferência sustentável do dispositivo resulta, de forma aproximada, no tempo que demora até o buffer ficar vazio. Exemplo: se eu permitir 4 GB de dados «sujos» e o suporte de destino atingir 500 MB/s, a gravação completa demora cerca de 8 segundos. Durante esse tempo, em caso de falha de energia ou de «kernel panic», as gravações mais recentes podem vir a faltar.

As aplicações podem fechar a janela através de fsync() ou fdatasync() reduzir, pois esses acessos obrigam o sistema de ficheiros a gravar dados (e, dependendo do modo de registo, também metadados) no suporte. Isto é mais dispendioso, mas essencial para bases de dados ou registos. Tenho o cuidado de garantir que os meus limites de «dirty» estejam de acordo com o comportamento de sincronização: frequentes fsync()-As visualizações beneficiam de uma taxa mais baixa rácio de sujidade, para que o kernel não reduza ainda mais o desempenho, uma vez que a persistência já é efetuada regularmente. Por outro lado, no caso de registos com grande volume de adições (append) que raramente são esvaziados, posso permitir buffers maiores – sempre tendo em conta o risco de perda aceitável.

As barreiras e as sequências de gravação também são importantes: os sistemas de ficheiros modernos utilizam comandos FUA/Flush para esvaziar corretamente as caches dos controladores. Em suportes sem proteção contra perda de energia (PLP), os buffers de grande dimensão aumentam o risco; com PLP ou proteção do cache de gravação, buffers maiores são frequentemente aceitáveis.

Rácio de fundo sujo: o valor-limiar suave

Com rácio_de_fundo_sujo Indico a partir de que percentagem da memória disponível os threads do flusher começam a escrever em segundo plano. Este valor não bloqueia as aplicações, mas inicia silenciosamente as tarefas de limpeza para que o buffer não fique sobrecarregado. Valores baixos geram gravações em segundo plano mais frequentes, mas mais uniformes, e suavizam os picos de latência. Valores mais elevados permitem um buffer maior, o que aumenta o débito em grandes gravações sequenciais, mas pode provocar picos de E/S consideráveis em caso de limpeza repentina. Normalmente, os valores predefinidos situam-se em cerca de dez por cento, mas eu ajusto esse limite consoante o suporte, a carga de trabalho e os requisitos de segurança.

Dirty Ratio: a travagem brusca

O parâmetro rácio de sujidade indica o limite a partir do qual o kernel limita os processos de escrita até que sejam regravadas páginas suficientes. Este limite rígido protege a memória contra uma inundação de dados não persistentes e, assim, tem um impacto direto nas aplicações assim que estas pretendem continuar a produzir dados. No caso das bases de dados, defino um valor mais baixo, para que as consultas mantenham tempos de resposta constantes e não surjam longas fases de flush. Por outro lado, para tarefas de cópia de segurança, utilizo buffers mais generosos, para transferir blocos de grande dimensão de forma eficiente. Os valores predefinidos habituais variam entre vinte e quarenta por cento, mas adapto sempre este intervalo à carga específica.

Interação e relações típicas

Ambos os valores-limite funcionam como Tandem e só surtem efeito quando atuam em conjunto. Mantengo sempre o valor de `dirty_background_ratio` inferior ao de `dirty_ratio`, para que o kernel inicie a tempo em segundo plano e a limitação severa raramente seja aplicada. Como regra geral, costumo escolher um valor entre um quarto e metade do limite máximo, ou seja, por exemplo, 5–10 para 20. Desta forma, o Writeback é iniciado com antecedência suficiente, sem reduzir desnecessariamente a taxa de transferência. Quem não respeitar esta relação irá enfrentar ou uma limitação prematura, ou um trabalho em segundo plano demasiado tardio, com picos de latência percetíveis.

Controlo por dispositivo e granularidade da camada de blocos

Para além dos limites globais, vale a pena dar uma olhadela ao nível do dispositivo. O Linux distribui a carga suja através dos chamados Dispositivos compatíveis (bdi). Em /sys/class/block//bdi/ Considero que parâmetros como max_ratio, que determinam a quantidade do «Dirty-Budget» global permitido que um único dispositivo pode utilizar. Em sistemas com unidades de disco lentas e rápidas a funcionar em paralelo, limito as unidades lentas para que não se tornem um gargalo.

Também é relevante a limitação da camada de blocos através de /sys/block//queue/wbt_lat_usec (Writeback Throttling). Com isto, defino uma latência-alvo; o kernel limita então a carga de escrita quando esta ultrapassa esse tempo-alvo. No caso de discos rígidos SATA, costumo definir valores conservadores para proteger a interatividade. Em unidades NVMe muito rápidas, desativo ou aumentei a latência-alvo, para que o controlador possa tirar partido da sua capacidade de paralelismo. Escolho o agendador de E/S (mq-deadline, BFQ, none) de acordo com as necessidades: o BFQ ajuda em sistemas interativos com carga mista, enquanto nenhum ou o mq-deadline costuma funcionar melhor em tarefas puramente de débito em NVMe.

A interação é decisiva: se rácio_de_fundo_sujo baixa, mas como o dispositivo está sujeito a limites rigorosos por parte do WBT, ocorrem, mesmo assim, congestionamentos visíveis. Por isso, calibro ambos os níveis em conjunto – limites globais de «dirty» para o tamanho do buffer e a camada de blocos para proteção contra a latência.

Rácio vs. bytes: valores predefinidos e variantes

Em sistemas com muita RAM Os valores percentuais aumentam rapidamente, atingindo grandes ordens de grandeza absolutas. Nesse caso, prefiro definir limites máximos absolutos com `dirty_bytes` e `dirty_background_bytes`, para limitar claramente a quantidade de memória tampão a cerca de 2–8 GB. Isto dissocia a regulação dos níveis de memória com fortes oscilações e mantém a quantidade de dados não persistentes calculável. A escolha continua a ser dinâmica: para servidores pequenos com pouca RAM, as percentagens são frequentemente suficientes. Quem dispõe de elevada capacidade, consegue muitas vezes planear melhor com valores em bytes.

Parâmetros Significado Predefinições típicas Quando é que se deve mudar? Nota
vm.dirty_background_ratio Início do Flush de fundo em percentagem ≈ 10% Em caso de flutuações de latência ou SSD/NVMe muito rápidos Mais baixo = latência mais suave, mais alto = mais buffer
vm.dirty_ratio Difícil Limite de estrangulamento em percentagem ≈ 20–40% Mais baixo no caso das bases de dados, mais elevado no caso das cópias de segurança Demasiado elevado → Possibilidade de bloqueios durante o flush
vm.dirty_background_bytes Início da limpeza em segundo plano em Bytes Desativado quando se utiliza o Ratio Grande quantidade de RAM, alvos de buffer fixos Anula os parâmetros do Ratio
vm.dirty_bytes Limite rígido de moderação em Bytes Desativado quando se utiliza o Ratio Grande capacidade de RAM, limite máximo programável Anula os parâmetros do Ratio

Cenários de carga de trabalho e recomendações

Cargas de escrita sequenciais, tais como Cópias de segurança beneficiam de grandes buffers e de uma escrita em segundo plano moderada, porque o kernel consegue escrever no suporte em grandes blocos. Aqui, costumo definir o dirty_ratio entre 30 e 40 por cento e o dirty_background_ratio entre 10 e 20 por cento. As bases de dados e as pequenas aplicações de E/S aleatória dependem de uma latência previsível; por isso, opto por 10–15 por cento de «hard» e 3–5 por cento de «soft». Para servidores mistos de Web e de aplicações, 15–20 por cento de «hard» e 5–10 por cento de «soft» revelam-se um bom compromisso. Estes intervalos servem como ponto de partida; depois, o que conta é a realidade medida do seu sistema.

Aspectos do sistema de ficheiros e opções de montagem

O percurso de reescrita termina no sistema de ficheiros – cuja estratégia determina as latências e a segurança. O Ext4 com dados=ordenados (Padrão) grava os dados de utilizador antes das confirmações do journal; data=writeback reduz a latência, mas coloca em risco os dados antigos em caso de falhas. O parâmetro comprometer= (segundos) determina a frequência com que o registo é guardado. Intervalos mais curtos reduzem a perda de dados, mas implicam mais operações de E/S. O XFS utiliza um design de registo bem desenvolvido; grandes tamanho do registo e um alinhamento adequado ajudam nas tarefas de alto rendimento. O Btrfs agrupa as gravações através do «copy-on-write» — o que estabiliza as latências, mas pode levar à fragmentação no caso de pequenas gravações aleatórias e SSDs com pouca capacidade. Opções como nodatacow ajudam na desfragmentação de determinados caminhos ou na desfragmentação direcionada, quando ocorrem picos de latência.

Além disso, tenho em conta que relatime/não há tempo (reduz as gravações de metadados), hora da preguiça (atime/mtime mais persistentes) e barreiras de registo. Especialmente em controladores RAID ou em máquinas virtuais, a semântica correta da cache é decisiva: caches de gravação mal configuradas anulam todo o trabalho de «dirty tuning».

E/S direta, O_SYNC e comportamento da aplicação

Nem todas as aplicações passam pelo cache de páginas. Com O_DIRECTO ou O_SYNC/O_DSYNC Os processos contornam partes da cache ou exigem persistência imediata. As bases de dados escrevem normalmente um WAL/registo de refazer de forma síncrona e as áreas de dados de forma assíncrona. Calibro os limites de «dirty» especialmente para os caminhos assíncronos, enquanto garanto a latência dos caminhos síncronos através de registos rápidos (NVMe, LUN dedicado). Quando as aplicações executam com muita frequência fsync() Quando se trata de chamadas de função, os buffers grandes são pouco úteis – a latência depende, nesse caso, mais do controlador, da profundidade da fila e do agendador de E/S do que de rácio de sujidade.

Afinação prática, passo a passo

Antes de cada alteração, verifico a valores reais com sysctl vm.dirty_ratio e sysctl vm.dirty_background_ratio, para registar a situação inicial. Para testes de curta duração, anoto os valores diretamente em /proc/sys/vm/por exemplo echo 15 > /proc/sys/vm/dirty_ratio e echo 5 > /proc/sys/vm/dirty_background_ratio. Se a alteração for permanente, vou guardá-la em /etc/sysctl.conf ou /etc/sysctl.d/*.conf. As alterações são implementadas com sysctl -p imediatamente, para que eu possa avaliar o efeito em tempo útil. Quem se aprofundar no tema das regras do sistema beneficiará de dicas práticas sobre o Ajuste de parâmetros sysctl em servidores produtivos.

Calcular valores: exemplos de cálculos

Gosto de começar com valores concretos. Exemplo 1: servidor web/de aplicações com 64 GB de RAM e NVMe. O objetivo é uma latência baixa. Eu defino dirty_background_bytes=1073741824 (1 GB) e dirty_bytes=3221225472 (3 GB). Com uma taxa de transferência NVMe sustentada de 2 GB/s, isso significa cerca de 0,5–1,5 segundos para esvaziar – adequado para cargas interativas. Exemplo 2: Nó de cópia de segurança com 128 GB de RAM, RAID SATA rápido com 800 MB/s. Escolho dirty_background_ratio=10, dirty_ratio=35. Em termos absolutos, são cerca de 12,8 GB e 44,8 GB; o RAID demora entre 16 e 56 segundos a esvaziar-se. Isso é aceitável, porque a tarefa não é interativa.

Exemplo 3: Servidor de base de dados com 256 GB de RAM, diário separado em NVMe, dados num conjunto de SSD. Estabeleço limites absolutos para evitar valores atípicos: dirty_background_bytes=2147483648 (2 GB), dirty_bytes=8589934592 (8 GB). Isto permite manter o tamanho da janela de falhas dentro do previsto e reduz as travagens bruscas durante os pontos de verificação.

Tempo de reescrita e parâmetros relacionados

Para além dos valores-limite, influenciam Temporizador o comportamento de gravação e, consequentemente, a sensação proporcionada pelas aplicações. Com vm.dirty_writeback_centisegundos controlo o intervalo em que o Kernel Flusher é ativado, enquanto vm.dirty_expire_centisecs define a idade máxima que as páginas sujas podem atingir. Intervalos mais curtos garantem flushes mais frequentes, mas de menor dimensão; intervalos mais longos poupam chamadas de E/S, mas arriscam a formação de lotes maiores. Só ajusto estes valores se as medições revelarem desvantagens reais, como, por exemplo, flushes demasiado raros em unidades NVMe rápidas. Quem adotar uma abordagem metódica evita oscilações entre uma atividade de writeback demasiado intensa e outra demasiado lenta.

Monitorização e ajuste fino

Após os ajustes, observo que contínuo os indicadores para tornar visíveis os sucessos e os efeitos secundários. Em /proc/meminfo Verifico o „Dirty“ e o „Writeback“ para ver os níveis dos buffers e os flushes ativos. Ferramentas como o iostat, o sar ou o atop mostram-me a taxa de transferência, as filas e as tendências de latência. Este artigo sobre o tema oferece uma boa introdução às métricas Analisar a espera de E/S. Só com base nestes dados é que vou reduzir ou aumentar os limites em pequenos passos, para que não surjam efeitos secundários inesperados.

Containers, cgroups e distribuição equitativa

Em ambientes de contentores, as cargas de trabalho partilham os mesmos mecanismos do kernel. O Cgroup-Writeback garante que as páginas sujas sejam atribuídas ao seu autor. Utilizo os controladores de E/S dos cgroups (blkcg) para limitar a largura de banda ou os IOPS por contentor, caso determinados inquilinos utilizem a memória tampão de forma demasiado agressiva. Limites absolutos de bytes ao nível do anfitrião (bytes_sujos) evitar que um único hóspede esgote todo o orçamento para despesas extraordinárias. Além disso, limito o espaço de armazenamento através de memória.max, para que o Writeback não reaja apenas quando houver pressão global. O objetivo continua a ser: nenhuma carga do convidado deve provocar limitações em todo o anfitrião do rácio de sujidade impor.

Ambientes de alojamento e máquinas virtuais

Em configurações multi-cliente e máquinas virtuais, presto atenção ao seguinte: Sobre-reserva de RAM e E/S, porque os limites percentuais têm um impacto diferente nessas áreas. Os limites absolutos em bytes podem impedir que determinados convidados acumulem demasiado buffer e atrasem os vizinhos. Tenho em conta a deduplicação de memória, o ballooning e as caches dos controladores, porque estes fatores se sobrepõem aos efeitos do buffer. No caso dos servidores geridos, é vantajoso que o fornecedor defina valores predefinidos adequados, para que os clientes tenham tempos de resposta constantes. Quem opera os seus próprios nós beneficia de configurações de perfil bem definidas para cada classe de carga de trabalho.

Equívocos e obstáculos frequentes

  • „Mais margem de segurança = cada vez mais rendimento.“ Isto não se aplica a cargas de trabalho com grande predominância de operações aleatórias ou a dispositivos com profundidade de fila reduzida. Buffers demasiado grandes geram picos de esvaziamento e filas.
  • „O dirty_ratio não afeta as leituras.“ Indiretamente, sim: as fases agressivas de reescrita substituem as páginas da cache e aumentam as latências de leitura.
  • „Os bytes e a razão somam-se.“ Não. Se definires variantes «Bytes», estas anularão as variantes «Ratio» correspondentes. Mantém-te claro.
  • „A função fsync() torna os limites de dados alterados irrelevantes.“ Não. Embora as sincronizações frequentes reduzam a janela de risco, o restante da carga continua sujeito aos valores-limite.
  • „Um suporte de dados rápido resolve tudo.“ Não, se o Block-Layer estiver a limitar a velocidade (WBT) ou se o sistema de ficheiros estiver montado de forma subótima.
  • „O Drop_caches é uma ferramenta de otimização.“ Esvaziar a cache distorce as medições e agrava os picos de latência. Em ambiente de produção, evito fazê-lo.

Resolução de problemas: sintomas típicos e soluções

Amontoar Picos de latência, começo por reduzir o valor limite de fundo, para que os flushes comecem mais cedo e as grandes ondas de gravação ocorram com menos frequência. Se as aplicações ficarem bloqueadas em determinados momentos, isso significa que, na maioria das vezes, o limite máximo está demasiado alto ou que o suporte não consegue lidar com os picos de flush que surgem. Nesses casos, reduzo o `dirty_ratio`, verifico as definições de `readahead` e analiso as opções de journaling do sistema de ficheiros. No caso de hardware NVMe muito rápido, aumento gradualmente o limiar de fundo para não limitar artificialmente a taxa de transferência. Após cada alteração, baseio-me nos dados de medição e não na intuição.

Resumo prático

Com poucos Parafusos de regulação Posso influenciar a forma como o Linux armazena dados de escrita em buffer, quando os flushers são iniciados e quando o kernel abranda. O «Dirty Background Ratio» garante uma limpeza silenciosa, enquanto o «Dirty Ratio» limita o consumo de RAM de forma mais rigorosa. A relação entre estes dois valores determina se o teu sistema se orienta mais para latências uniformes ou para o máximo rendimento. Registo os valores predefinidos, faço alterações em pequenos passos e analiso as medições de forma consistente. Assim, cria-se uma configuração que equilibra de forma razoável a carga de trabalho, o suporte e o risco e que, na prática, funciona de forma visivelmente mais rápida.

Artigos actuais