Limitar a liberação de segundo plano do Linux (páginas sujas)


26

A liberação em segundo plano no Linux ocorre quando há excesso de dados gravados pendentes (ajustável via / proc / sys / vm / dirty_background_ratio) ou é atingido um tempo limite para gravações pendentes (/ proc / sys / vm / dirty_expire_centisecs). A menos que outro limite seja atingido (/ proc / sys / vm / dirty_ratio), mais dados gravados podem ser armazenados em cache. Gravações adicionais serão bloqueadas.

Em teoria, isso deve criar um processo em segundo plano, escrevendo páginas sujas sem perturbar outros processos. Na prática, isso perturba qualquer processo que faça leitura não armazenada em cache ou gravação síncrona. Seriamente. Isso ocorre porque a liberação em segundo plano na verdade grava na velocidade de 100% do dispositivo e qualquer outra solicitação de dispositivo nesse momento será atrasada (porque todas as filas e caches de gravação na estrada são preenchidos).

Existe uma maneira de limitar a quantidade de solicitações por segundo que o processo de liberação executa, ou priorizar efetivamente outras E / S de outros dispositivos?


Talvez essa seja uma boa pergunta para enviar à lista de discussão do kernel do linux vger.kernel.org/vger-lists.html#linux-kernel

Qual planejador de E / S você está usando?
3dinfluence

Tentei vários (cfq, prazo), mas acho que eles só funcionam de maneira confiável quando nenhum cache de gravação com bateria está incluído. Como uma matriz de disco, eu tenho 1 GiB de dados na velocidade do barramento PCIe (RAM) e, em seguida, atinge o muro da realidade. Vários segundos zero de E / S para todos os LUNs. Limitar as descargas (pelo menos em segundo plano) a uma estimativa aproximada da velocidade real do dispositivo resolveria esse problema de congestionamento.
Korkman

1
Recentemente, tomei conhecimento de / sys / block / sdX / queue / nr_requests como um dos principais ajustáveis. A redução para o mínimo (= 4 no meu caso) melhora muito a latência de carga simultânea: as gravações aleatórias por segundo do Sysbench fsync saltaram de 4 (!) Para 80-90 enquanto escreviam na velocidade do barramento com dd. O desempenho não carregado parece não ser afetado. Os agendadores são todos iguais, noop ou prazo parece ideal. Isso pode ser verdade para a maioria das configurações de BBWC.
Korkman

Respostas:


20

Após muitos testes comparativos com o sysbench, chego a esta conclusão:

Para sobreviver (em termos de desempenho) a uma situação em que

  • um processo de cópia maligna inunda páginas sujas
  • e cache de gravação de hardware está presente (possivelmente também sem isso)
  • e leituras ou gravações síncronas por segundo (IOPS) são críticas

basta despejar todos os elevadores, filas e caches de páginas sujos. O local correto para páginas sujas está na RAM desse cache de gravação de hardware.

Ajuste dirty_ratio (ou novos dirty_bytes) o mais baixo possível, mas fique de olho na taxa de transferência seqüencial. No meu caso particular, 15 MB foram ótimos ( echo 15000000 > dirty_bytes).

Isso é mais um hack do que uma solução, porque agora gigabytes de RAM são usados ​​apenas para cache de leitura, em vez de cache sujo. Para que o cache sujo funcione bem nessa situação, o descarregador em segundo plano do kernel do Linux precisará calcular a velocidade com que o dispositivo subjacente aceita solicitações e ajustar a descarga em segundo plano de acordo. Díficil.


Especificações e referências para comparação:

Testado ao ddinserir zeros no disco, o sysbench mostrou enorme sucesso , aumentando 10 threads de gravações fsync em 16 kB de 33 a 700 IOPS (limite de inatividade: 1500 IOPS) e um thread único de 8 a 400 IOPS.

Sem carga, os IOPS não foram afetados (~ 1500) e a taxa de transferência foi ligeiramente reduzida (de 251 MB / s para 216 MB / s).

dd ligar:

dd if=/dev/zero of=dumpfile bs=1024 count=20485672

para sysbench, o test_file.0 foi preparado para não ser comparado com:

dd if=/dev/zero of=test_file.0 bs=1024 count=10485672

chamada sysbench para 10 threads:

sysbench --test=fileio --file-num=1 --num-threads=10 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

chamada sysbench para um thread:

sysbench --test=fileio --file-num=1 --num-threads=1 --file-total-size=10G --file-fsync-all=on --file-test-mode=rndwr --max-time=30 --file-block-size=16384 --max-requests=0 run

Blocos menores mostraram números ainda mais drásticos.

--file-block-size = 4096 com 1 GB dirty_bytes:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 30 Write, 30 Other = 60 Total
Read 0b  Written 120Kb  Total transferred 120Kb  (3.939Kb/sec)
      0.98 Requests/sec executed

Test execution summary:
      total time:                          30.4642s
      total number of events:              30
      total time taken by event execution: 30.4639
      per-request statistics:
           min:                                 94.36ms
           avg:                               1015.46ms
           max:                               1591.95ms
           approx.  95 percentile:            1591.30ms

Threads fairness:
      events (avg/stddev):           30.0000/0.00
      execution time (avg/stddev):   30.4639/0.00

--file-block-size = 4096 com 15 MB dirty_bytes:

sysbench 0.4.12:  multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 13524 Write, 13524 Other = 27048 Total
Read 0b  Written 52.828Mb  Total transferred 52.828Mb  (1.7608Mb/sec)
    450.75 Requests/sec executed

Test execution summary:
      total time:                          30.0032s
      total number of events:              13524
      total time taken by event execution: 29.9921
      per-request statistics:
           min:                                  0.10ms
           avg:                                  2.22ms
           max:                                145.75ms
           approx.  95 percentile:              12.35ms

Threads fairness:
      events (avg/stddev):           13524.0000/0.00
      execution time (avg/stddev):   29.9921/0.00

--file-block-size = 4096 com 15 MB dirty_bytes no sistema ocioso:

sysbench 0.4.12: benchmark de avaliação de sistema multiencadeado

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
1 files, 10Gb each
10Gb total file size
Block size 4Kb
Number of random requests for random IO: 0
Read/Write ratio for combined random IO test: 1.50
Calling fsync() after each write operation.
Using synchronous I/O mode
Doing random write test
Threads started!
Time limit exceeded, exiting...
Done.

Operations performed:  0 Read, 43801 Write, 43801 Other = 87602 Total
Read 0b  Written 171.1Mb  Total transferred 171.1Mb  (5.7032Mb/sec)
 1460.02 Requests/sec executed

Test execution summary:
      total time:                          30.0004s
      total number of events:              43801
      total time taken by event execution: 29.9662
      per-request statistics:
           min:                                  0.10ms
           avg:                                  0.68ms
           max:                                275.50ms
           approx.  95 percentile:               3.28ms

Threads fairness:
      events (avg/stddev):           43801.0000/0.00
      execution time (avg/stddev):   29.9662/0.00

Sistema de teste:

  • Adaptec 5405Z (cache de gravação de 512 MB com proteção)
  • Intel Xeon L5520
  • 6 GiB de RAM a 1066 MHz
  • Placa-mãe Supermicro X8DTN (chipset 5520)
  • 12 discos Seagate Barracuda 1 TB
    • 10 no software Linux RAID 10
  • Kernel 2.6.32
  • Sistema de arquivos xfs
  • Debian instável

Em resumo, agora tenho certeza de que essa configuração terá um bom desempenho em situações ociosas, com carga alta e até com carga total para o tráfego do banco de dados que, de outra forma, teria passado fome pelo tráfego seqüencial. A taxa de transferência seqüencial é superior a dois links de gigabit, de qualquer maneira, portanto, não há problema em reduzi-la um pouco.


Qual é a sua metodologia para chegar à parte '15 MB para dirty_buffers é ideal'?
1516 Marcin

1
Tentativa e erro. Como, mude metade da quantia da próxima vez, etc., até que eu tenha apenas 15 MB e OK IOPS. O kernel atual 3.2 pode se comportar muito diferente, BTW.
22412 korkman

2
Só queria agradecer por me colocar no caminho certo. Teve alguns problemas semelhantes com um nó XenServer. Acabou sendo um cache PHP-FPM / APC causando páginas sujas. O ajuste do modelo de memória em cache da APC resolveu o problema para nós. DiskIO passou de utilização de 20% a 0.
jeffatrackaid

Logicamente dirty_bytes, mal deve ser alto o suficiente para não travar as CPUs enquanto os processos estão gravando, se o processo estiver gravando em média com a taxa de transferência do dispositivo. Se o código do seu aplicativo estiver realizando ciclos de computação enorme seguidos da gravação de uma quantidade enorme de dados, será muito difícil otimizar porque as médias de tempo curto diferem muito das médias de tempo longo. A solução correta seria ajustar as dirty_bytesconfigurações específicas do processo , mas o Linux não suporta essas coisas, tanto quanto eu sei.
Mikko Rantalainen

3

Embora o ajuste dos parâmetros do kernel tenha parado o problema, é possível que seus problemas de desempenho tenham resultado de um bug no controlador Adaptec 5405Z que foi corrigido em uma atualização de firmware de 1 de fevereiro de 2012. As notas de versão dizem "Corrigido um problema em que o firmware podia travar durante um alto estresse de E / S". Talvez espalhar a E / S como você fez foi suficiente para impedir que esse bug fosse acionado, mas isso é apenas um palpite.

Aqui estão as notas de versão: http://download.adaptec.com/pdfs/readme/relnotes_arc_fw-b18937_asm-18837.pdf

Mesmo que esse não seja o caso da sua situação específica, achei que isso poderia beneficiar os usuários que se depararem com esta postagem no futuro. Vimos algumas mensagens como as seguintes em nossa saída dmesg, que finalmente nos levaram à atualização do firmware:

aacraid: Host adapter abort request (0,0,0,0)
[above was repeated many times]
AAC: Host adapter BLINK LED 0x62
AAC0: adapter kernel panic'd 62.
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000000
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028
Result: hostbyte=DID_OK driverbyte=DRIVER_TIMEOUT,SUGGEST_OK
sd 0:0:0:0: timing out command, waited 360s
sd 0:0:0:0: Unhandled error code
sd 0:0:0:0: SCSI error: return code = 0x06000028

Aqui estão os números de modelo dos controladores Adaptec RAID listados nas notas de versão do firmware que possui a correção de interrupção de E / S alta: 2045, 2405, 2405Q, 2805, 5085, 5405, 5405Z, 5445, 5445Z, 5805, 5805Q, 5805Z, 5805ZQ, 51245, 51645, 52445.


1
Uau, obrigado pela sua contribuição. Embora esse não fosse o meu caso, você me deu mais um motivo para evitar o HW RAID completamente e passar para as configurações apenas do HBA. O HW RAID ainda tem a vantagem do BBWC, mas com coisas como o bcache migrando para o kernel, até isso desaparece. O lado contrário do HW RAID é exatamente o tipo de bugs de firmware que você descreve. Eu tinha outro sistema com configuração DRBD e alta carga de E / S, causando redefinições de firmware; portanto, não é raro encontrar isso (pode ter sido exatamente esse bug).
Korkman

1

Um kernel que inclui "WBT":

Melhorias na camada de blocos , LWN.net

Com a otimização de write-back, [a camada de bloco] tenta obter o desempenho máximo sem latência excessiva de E / S, usando uma estratégia emprestada do agendador de rede CoDel. O CoDel rastreia a latência mínima observada dos pacotes de rede e, se isso exceder um valor limite, começa a soltar pacotes. A eliminação de gravações é desaprovada no subsistema de E / S, mas uma estratégia semelhante é seguida, pois o kernel monitora a latência mínima de leituras e gravações e, se isso exceder um valor limite, começa a diminuir a quantidade de gravações em segundo plano. isso está sendo feito. Esse comportamento foi adicionado na versão 4.10; Axboe disse que bons resultados foram vistos.

O WBT não requer mudança para a nova camada de blocos blk-mq. Dito isto, ele não funciona com os planejadores de E / S CFQ ou BFQ. Você pode usar o WBT com os planejadores deadline / mq-deadline / noop / none. Acredito que ele também funcione com o novo agendador de E / S "kyber".

Além de dimensionar o tamanho da fila para controlar a latência, o código WBT limita o número de solicitações de write-back em segundo plano como uma proporção do limite da fila calculado.

A configuração de tempo de execução é na /sys/class/block/*/queue/wbt_lat_usec.

As opções de configuração de compilação a serem procuradas são

/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT=y
/boot/config-4.20.8-200.fc29.x86_64:# CONFIG_BLK_WBT_SQ is not set
/boot/config-4.20.8-200.fc29.x86_64:CONFIG_BLK_WBT_MQ=y

Sua declaração do problema é confirmada 100% pelo autor do WBT - muito bem :-).

Bloco [PATCHSET]: limitação de write-back em buffer

Desde o início dos tempos, nosso write-back com buffer em segundo plano foi péssimo. Quando realizamos writeback em buffer em segundo plano, ele deve ter pouco impacto na atividade em primeiro plano. Essa é a definição de atividade em segundo plano ... Mas, desde que me lembro, escritores pesados ​​em buffer não se comportaram assim. Por exemplo, se eu fizer algo assim:

$ dd if=/dev/zero of=foo bs=1M count=10k

no meu laptop e tente iniciar o chrome, ele basicamente não será iniciado antes que a gravação em buffer seja concluída. Ou, para cargas de trabalho orientadas ao servidor, em que a instalação de um grande RPM (ou similar) afeta negativamente as leituras ou sincronizações de banco de dados. Quando isso acontece, as pessoas gritam comigo.

Os resultados de alguns testes recentes podem ser encontrados aqui:

https://www.facebook.com/axboe/posts/10154074651342933

Veja as postagens anteriores para obter uma descrição maior do patchset.


Fico feliz em ver que o problema é reconhecido e tratado dentro do kernel agora. Lembre-se de que o blk-mq é relativamente novo e talvez ainda não esteja maduro .
korkman 22/02

@ Korkman suspiro, acho que vou alterar a citação para evitar a falsa implicação. Concordo que isso é algo adicionado nos últimos dois anos, ainda pode haver regressões de desempenho ou coisa pior. AFAIR, o mantenedor, descarta a correção de corrupção de dados no sentido de que é um golpe de sorte. Se você estiver usando as versões do kernel em que o blk-mq foi desenvolvido, é discutível quanto o uso da camada de bloco "legado" evitará bugs. O bug de suspensão que corrigi foi um bug que se originou no blk-mq, depois foi refatorado ou algo assim e afetou ambos. github.com/torvalds/linux/commit/1dc3039bc87a
sourcejedi

0

Qual é a sua média para Dirty em / proc / meminfo? Normalmente, isso não deve exceder o seu / proc / sys / vm / dirty_ratio. Em um servidor de arquivos dedicado, o dirty_ratio está definido como uma porcentagem muito alta de memória (90), pois nunca a excederá. Sua sujeira_ração é muito baixa, quando você a atinge, tudo estraga, aumente.


O problema não é que os processos estão sendo bloqueados ao pressionar dirty_ratio. Eu estou bem com isso. Mas o processo "em segundo plano" que grava dados sujos nos discos preenche filas sem piedade e mata o desempenho de IOPS. É chamado fome de IO, eu acho. De fato, definir dirty_ratio_bytes extremamente baixo (como 1 MB) ajuda muito, porque a liberação ocorrerá quase imediatamente e as filas serão mantidas vazias. A desvantagem é possivelmente menor taxa de transferência para sequencial, mas tudo bem.
Korkman

Você desligou todos os elevadores? O que mais você ajustou de um sistema de baunilha?
15554 Lucas

1
Veja minha auto-resposta. O final da história foi remover o cache sujo e deixar essa parte para o controlador HW. Os elevadores são meio irrelevantes com o cache de gravação HW no local. O controlador possui seus próprios algoritmos de elevador, portanto, ter qualquer elevador em software apenas acrescenta sobrecarga.
Korkman

O elevador no software é uma troca: sacrifique a latência para melhorar a largura de banda. Por exemplo, imagine 100K de operações de gravação na fila de software enviada em ordem aleatória; se o elevador do software pode solicitar essas operações usando um buffer enorme, pode acabar enviando apenas solicitações 5K muito maiores ao dispositivo. No entanto, como resultado, a latência precisa ser aumentada em 100K ops, porque pode ser que as primeiras 2K ops e as 1K ops estejam realmente próximas umas das outras no dispositivo. Sem latência adicional, será impossível mesclar esses.
Mikko Rantalainen
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.