A resposta (como eu sei agora): simultaneidade .
Resumindo : Minha gravação seqüencial , usando dd
ou ao copiar um arquivo (como ... no uso diário), torna-se um pseudo -random escrever (ruim) porque quatro threads estão trabalhando simultaneamente ao escrever os dados criptografados para o dispositivo de bloco após a criptografia simultânea (bom).
Mitigação (para kernels "mais antigos")
O efeito negativo pode ser atenuado aumentando a quantidade de solicitações enfileiradas na fila do agendador de E / S da seguinte forma:
echo 4096 | sudo tee /sys/block/sdc/queue/nr_requests
No meu caso, isso quase triplica (~ 56MB / s) a taxa de transferência para o teste de dados aleatórios de 4GB explicado na minha pergunta. Obviamente, o desempenho ainda fica aquém dos 100MB / s em comparação com o IO não criptografado.
Investigação
Multicore blktrace
Eu investiguei ainda mais o cenário problemático em que um btrfs é colocado no topo de um dispositivo de bloqueio criptografado LUKS. Para me mostrar quais instruções de gravação são emitidas para o dispositivo de bloco real, usei blktrace
da seguinte forma:
sudo blktrace -a write -d /dev/sdc -o - | blkparse -b 1 -i - | grep -w D
O que isto faz é (até onde eu pude compreender) rastrear o pedido de E / S para /dev/sdc
que são do tipo " escrever ", então analisar isso para saída legível por humanos mas restringir ainda mais saída para ação " D ", que é (de acordo com man blkparse
) " IO emitido para o driver ".
O resultado foi algo assim (consulte cerca de 5000 linhas de saída do log multicore ):
8,32 0 32732 127.148240056 3 D W 38036976 + 240 [ksoftirqd/0]
8,32 0 32734 127.149958221 3 D W 38038176 + 240 [ksoftirqd/0]
8,32 0 32736 127.160257521 3 D W 38038416 + 240 [ksoftirqd/0]
8,32 1 30264 127.186905632 13 D W 35712032 + 240 [ksoftirqd/1]
8,32 1 30266 127.196561599 13 D W 35712272 + 240 [ksoftirqd/1]
8,32 1 30268 127.209431760 13 D W 35713872 + 240 [ksoftirqd/1]
- Coluna 1: maior, menor do dispositivo de bloco
- Coluna 2: ID da CPU
- Coluna 3: número de sequência
- Coluna 4: data e hora
- Coluna 5: ID do processo
- Coluna 6: ação
- Coluna 7: Dados da RWBS (tipo, setor, tamanho)
Este é um recorte da saída produzida enquanto dd
'dos dados aleatórios de 4GB no sistema de arquivos montado. É claro que pelo menos dois processos estão envolvidos. O log restante mostra que todos os quatro processadores estão realmente trabalhando nele. Infelizmente, as solicitações de gravação não são mais ordenadas. Enquanto CPU0 está escrevendo em algum lugar em torno do setor 38038416th, CPU1, que está programado posteriormente, está escrevendo em algum lugar em torno do setor 35713872nd. Isso é ruim.
singlecore blktrace
Eu fiz o mesmo experimento depois de desabilitar o multi-threading e desabilitar o segundo núcleo da minha CPU. Naturalmente, apenas um processador está envolvido em escrever no gravador. Mas, mais importante, a solicitação de gravação é apropriadamente sequencial, e é por isso que o desempenho total de gravação de ~ 170MB / s é obtido na mesma configuração.
Dê uma olhada em cerca de 5000 linhas de saída no log de singlecore .
Discussão
Agora que conheço a causa e os termos de pesquisa apropriados do Google, as informações sobre esse problema estão surgindo na superfície. Como se constata, eu não sou o primeiro a notar.
- Há quatro anos, um patch trouxe multithreaded dm-crypt para o kernel. Esse commit corresponde exatamente às minhas descobertas.
- Dois anos atrás, os patches foram discutidos melhorando o desempenho do dm-crypt , incluindo -ordenação de solicitações de gravação.
- Um ano atrás, o tópico ainda era discutido .
- Recentemente, um patch habilitando classificação para o dm-crypt foi finalmente submetido ao kernel.
- Existe um e-mail interessante com testes de desempenho (o que eu não fiz leia muito de) sobre este fenômeno.
Corrigido nos kernels atuais (> = 4.0.2)
Porque eu (mais tarde) encontrei o kernel commit obviamente direcionado a esse problema exato, eu queria tentar um kernel atualizado. [Depois de compilá-lo e depois descobrir que já está em debian/sid
] Acontece que o problema é realmente corrigido. Eu não sei a versão exata do kernel em que a correção apareceu, mas o commit original dará pistas a qualquer pessoa interessada.
Para o registro:
$ uname -a
Linux t440p 4.0.0-1-amd64 #1 SMP Debian 4.0.2-1 (2015-05-11) x86_64 GNU/Linux
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test bs=1M conv=fsync
4294967296 bytes (4.3 GB) copied, 29.7559 s, 144 MB/s
Uma dica para Mikulas Patocka, autor do commit.