
Depois de ler alguns artigos sobre o cache de páginas VFS do Linux e os parâmetros ajustáveis, dirty_ratio
tive a impressão de que o cache de páginas funcionaria como camada de cache de leitura e gravação.
Mas usar o teste simples abaixo funciona bem para melhorar a velocidade de leitura de arquivos localizados no cache da página, mas que não parecem funcionar nas gravações.
por exemplo
Limpe o cache e grave no arquivo.
# swapoff -a
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/dev/zero of=/home/flo/test bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.182474 s, 172 MB/s
Verifique se o arquivo está realmente no cache da página
# vmtouch /home/flo/test
Files: 1
Directories: 0
Resident Pages: 7680/7680 30M/30M 100%
Elapsed: 0.000673 seconds
Leia o arquivo para confirmar se realmente vem do cache.
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.00824169 s, 3.8 GB/s
Elimine o cache e leia novamente para provar a diferença de velocidade.
# echo 3 > /proc/sys/vm/drop_caches
# dd if=/home/flo/test of=/dev/null bs=1M count=30
30+0 records in
30+0 records out
31457280 bytes (31 MB) copied, 0.132531 s, 237 MB/s
Como não estou usando DIRECT_IO com dd, esperava que o cache da página fosse usado como um tipo de cache de write-back. E com base em dirty_ratio
ou dirty_expire_centiseconds
... eventualmente os dados seriam confirmados no disco.
Alguém pode explicar como o VFS lida com o processo de leitura e gravação de maneira diferente, especialmente durante as gravações, e por que não há ganho de velocidade.
Existe alguma maneira de tornar o vfs mais agressivo no cache de gravação para que ele se comporte mais como o cache de write-back que você pode encontrar em um controlador RAID, por exemplo.
Obrigado
fLo
Responder1
man ext4 tem esta introdução sobre auto_da_alloc
a opção (no):
Muitos aplicativos quebrados não usam fsync()...
Parece haver uma longa história (alguma tragédia sobre perda de dados) por trás disso. Tem a ver comalocação atrasadade blocos do sistema de arquivos. Ext2/3 não tinha isso, mas é um recurso muito importante não apenas do ext4.
Se o aplicativo não sincronizar, nem o usuário manualmente, e o kernel somente após 30 segundos, é melhor que o sistema de arquivos faça isso imediatamente quando alguma reescrita de arquivo estiver envolvida. Caso contrário, com o DA, coisas ruins podem acontecer facilmente em caso de falha de energia. Coisas piores do que apenas perder as últimas alterações.
Sem conv=notruncate
o comando dd atua como um "aplicativo" ao substituir. É necessário se livrar do arquivo existente para criar o novo, caso contrário você obterá uma mistura se o arquivo existente for mais longo.
Com mount -o remount,noauto_da_alloc ...
você pode desativar esse comportamento no ext4. Agora a escrita do bloco pode ser feita muito tempo após o truncamento.
Nas próximasnível de agressãoseria aumentar o tempo de expiração de 30s e o intervalo de verificação de 5s (os valores dirty_..._centisecs em /proc/sys/vm/) para os writebacks periódicos. Com o padrão 30/5, alguns novos arquivos serão gravados meio minuto depois, a menos que você seja muito rápido para excluí-los mais rapidamente.
Quanto mais agressivo o VFS for com as páginas não utilizadas, menos agressivo o sistema de arquivos deverá ser com o dispositivo de bloco.
Opções de montagem e parâmetros de writeback
]# findmnt --real
TARGET SOURCE FSTYPE OPTIONS
/ /dev/sda3 ext4 rw,relatime,noauto_da_alloc
|-/root/sda1 /dev/sda1 ext2 rw,relatime
`-/root/16 /dev/sda16 ext4 rw,relatime
Em uma configuração como essa, uma substituição é sincronizada imediatamente no sda16, mas não nos outros dois.
No momento eu (acho que) desliguei completamente o write-back periódico.
]# grep '' /proc/sys/vm/*centisecs
/proc/sys/vm/dirty_expire_centisecs:720000
/proc/sys/vm/dirty_writeback_centisecs:0
E agora finalmente estou reunindo páginas sujas:
]# grep nr_dirty /proc/vmstat
nr_dirty 10077
nr_dirty_threshold 437320
nr_dirty_background_threshold 174671
EUtentarpara reuni-los e chegar de alguma forma perto da proporção de fundo padrão de 10% - fui sincronizado ontem quando fui suspender para o RAM. Faz sentido: quem quer dormir com MBs de páginas sujas?
mm/writeback.c
é muito complexo em detalhes, dizem os comentários. Um problema é não perder o ponto de estrangulamento quando "1000 dd começam a sujar de uma vez". O "Writeback" parece ter como objetivo uma proporção de 10% de glicemia, no longo prazo. Como meu exemplo acima mostra, esses 10% (da RAM total/disponível) demoram muito para serem preenchidos sob uso normal (mínimo). Um minuto de navegação suja 1.000 páginas, aproximadamente.
Depois da teoria, a prova específica
Testei 10 blocos em dois dos sistemas de arquivos listados acima:
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0076396 s, 1.4 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00514406 s, 2.0 GB/s
-> com noauto_da_alloc na partição raiz (sda3, acima) a substituição é ainda mais rápida.
No ext4 montado padrão (sda16 acima), ele fica mais lento:
]# rm test10
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.00800839 s, 1.3 GB/s
]# dd if=/dev/zero of=test10 bs=1M count=10
10+0 records in
10+0 records out
10485760 bytes (10 MB, 10 MiB) copied, 0.0740824 s, 142 MB/s
... porque toda a substituição é sincronizada, como vmstat 1 |cut...
mostra:
0 0
0 0
0 0
-----io----
bi bo
0 10240
0 0
0 0
Manualmente sync
com alocação atrasada
O bom disso é que você faz isso quando quiser e pode fazer isso em arquivos únicos, mas também em unidades inteiras.
Além disso: desmontar, desligar (e suspender) está incluído.
O ruim é: risco de "corrupção" de comprimento zero quando ocorre uma falha/falha de energia entre uma gravação (sobre) e uma sincronização. O que significa que você realmente só tem como segurança o que coloca em um ou dois armazenamentos externos.
Não consigo encontrar um resultado final. Não existe uma solução fácil, apenas explicações longas (mas pelo menos lógicas).
Responder2
Para ver o comportamento rápido, tenho que fazer rm test
primeiro. Por exemplo, vejo dd
o relatório de 1 GB/s em vez de 150 MB/s.
Referências:
auto_da_alloc
emhomem ext4.- Artigo LWN.net "ext4 e perda de dados".
- O XFS faz o mesmo neste caso, mas não no outro caso o ext4 (renomeando um arquivo existente):https://www.spinics.net/lists/xfs/msg36717.html.
Embora as referências apenas expliquem por que pensei em tentar isso, na verdade não explicam por que causa o bloqueio do IO.
No meu computador, o bloqueio parecia acontecer apenas dentro do novo código WBT ("writeback throttling")... que foi adicionado em 2016,depoisvocê fez sua pergunta. eu não analiseipor queisso causaria isso. E desapareceu quando o WBT foi desativado.
Minha versão do kernel é 4.18.16-200.fc28.x86_64
.
strace -T
mostra que todo o tempo foi gasto em close(), o que faz mais sentido para mim. Tentei usar perf
também. Não funcionou como deveria, mas mostrou rastreamentos de pilha como
dd 17068 [003] 475165.381526: sched:sched_switch: dd:17068 [120] T ==> kworker/3:1H:19326 [100]
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c172 __sched_text_start+0x352 ([kernel.kallsyms])
ffffffffa390c6a8 schedule+0x28 ([kernel.kallsyms])
ffffffffa30def32 io_schedule+0x12 ([kernel.kallsyms])
ffffffffa3461ed7 wbt_wait+0x337 ([kernel.kallsyms])
ffffffffa342ee33 blk_queue_bio+0x123 ([kernel.kallsyms])
ffffffffa342d114 generic_make_request+0x1a4 ([kernel.kallsyms])
ffffffffa342d3c5 submit_bio+0x45 ([kernel.kallsyms])
ffffffffa3377d78 ext4_io_submit+0x48 ([kernel.kallsyms])
ffffffffa335da2c ext4_writepages+0x70c ([kernel.kallsyms])
ffffffffa3209311 do_writepages+0x41 ([kernel.kallsyms])
ffffffffa31f808e __filemap_fdatawrite_range+0xbe ([kernel.kallsyms])
ffffffffa334b9ec ext4_release_file+0x6c ([kernel.kallsyms])
ffffffffa32a9d4e __fput+0xae ([kernel.kallsyms])
ffffffffa30cf474 task_work_run+0x84 ([kernel.kallsyms])
ffffffffa3003e6e exit_to_usermode_loop+0xce ([kernel.kallsyms])
ffffffffa300425d do_syscall_64+0x14d ([kernel.kallsyms])
ffffffffa3a00088 entry_SYSCALL_64_after_hwframe+0x44 ([kernel.kallsyms])
7fcca3a60654 __close+0x14 (/usr/lib64/libc-2.27.so)
o que me lembrou que eu estava testando o deadline
agendador de E/S, com WBT ("writeback throttling") habilitado. Desativar o WBT (inclusive mudando para CFQ, que é incompatível) me deu um comportamento rápido novamente!
Os perf
comandos que usei para ver isso foram:
sudo perf record -e sched:sched_stat_sleep -e sched:sched_switch -e sched:sched_process_exit -gP -o ~/perf.data dd if=/dev/zero of=test bs=1M count=30
sudo perf script -i ~/perf.data | cat
Responder3
Só não use dd
. Por exemplo, use cp
e você obterá o pagecache para gravações, tudo bem.