Estou investigando um problema em que a criptografia de um dispositivo de bloco impõe uma enorme penalidade de desempenho ao gravá -lo. Horas de leitura e experiências na Internet não me proporcionaram um entendimento adequado, muito menos uma solução.
A questão é resumida: por que obtenho velocidades de gravação perfeitamente rápidas ao colocar um btrfs em um dispositivo de bloco (~ 170MB / s), enquanto a velocidade de gravação cai (~ 20MB / s) ao colocar um dm-crypt / LUKS entre o sistema de arquivos e dispositivo de bloco, embora o sistema seja mais do que capaz de sustentar uma taxa de transferência de criptografia suficientemente alta?
Cenário
/home/schlimmchen/random
é um arquivo de 4,0 GB preenchido com dados /dev/urandom
anteriores.
dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096
Lê-lo é super rápido:
$ dd if=/home/schlimmchen/Documents/random of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 6.58036 s, 648 MB/s
$ dd if=/home/schlimmchen/Documents/random of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 0.786102 s, 5.4 GB/s
(na segunda vez, o arquivo foi obviamente lido do cache).
Btrfs não criptografados
O dispositivo é formatado diretamente com btrfs (nenhuma tabela de partição no dispositivo de bloco).
$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
A velocidade de gravação chega a ~ 170MB / s:
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test1 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 27.1564 s, 157 MB/s
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test2 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 25.1882 s, 169 MB/s
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test3 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 29.8419 s, 143 MB/s
A velocidade de leitura está bem acima de 200 MB / s.
$ dd if=/mnt/dd-test1 of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 19.8265 s, 215 MB/s
$ dd if=/mnt/dd-test2 of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 19.9821 s, 213 MB/s
$ dd if=/mnt/dd-test3 of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 19.8561 s, 215 MB/s
Btrfs criptografados no dispositivo de bloco
O dispositivo está formatado com LUKS e o dispositivo resultante está formatado com btrfs:
$ sudo cryptsetup luksFormat /dev/sdf
$ sudo cryptsetup luksOpen /dev/sdf crypt
$ sudo mkfs.btrfs /dev/mapper/crypt
$ sudo mount /dev/mapper/crypt /mnt
$ sudo chmod 777 /mnt
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test1 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 210.42 s, 20.3 MB/s
$ dd if=/home/schlimmchen/Documents/random of=/mnt/dd-test2 bs=1M
4265841146 bytes (4.3 GB) copied, 207.402 s, 20.6 MB/s
A velocidade de leitura sofre apenas um pouco (por que isso acontece?):
$ dd if=/mnt/dd-test1 of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 22.2002 s, 192 MB/s
$ dd if=/mnt/dd-test2 of=/dev/null bs=1M
4265841146 bytes (4.3 GB) copied, 22.0794 s, 193 MB/s
luksDump: http://pastebin.com/i9VYRR0p
Btrfs criptografados no arquivo btrfs no dispositivo de bloco
A velocidade de gravação "dispara" para mais de 150 MB / s ao gravar em um arquivo criptografado. Coloquei um btrfs no dispositivo de bloco, aloquei um arquivo de 16GB que eu lukfsFormat
montei e montei.
$ sudo mkfs.btrfs /dev/sdf -f
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
$ dd if=/dev/zero of=/mnt/crypted-file bs=1M count=16384 conv=fsync
17179869184 bytes (17 GB) copied, 100.534 s, 171 MB/s
$ sudo cryptsetup luksFormat /mnt/crypted-file
$ sudo cryptsetup luksOpen /mnt/crypted-file crypt
$ sudo mkfs.btrfs /dev/mapper/crypt
$ sudo mount /dev/mapper/crypt /tmp/nested/
$ dd if=/home/schlimmchen/Documents/random of=/tmp/nested/dd-test1 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 26.4524 s, 161 MB/s
$ dd if=/home/schlimmchen/Documents/random of=/tmp/nested/dd-test2 bs=1M conv=fsync
4265841146 bytes (4.3 GB) copied, 27.5601 s, 155 MB/s
Por que o desempenho de gravação está aumentando assim? O que esse aninhamento específico de sistemas de arquivos e dispositivos de bloco alcança para ajudar em altas velocidades de gravação?
Configuração
O problema é reproduzível em dois sistemas executando a mesma distribuição e kernel. No entanto, também observei as baixas velocidades de gravação no kernel 3.19.0 no System2.
- Equipamento: SanDisk Extreme 64GB USB3.0 USB Stick
- System1: Intel NUC 5i5RYH, i5-5250U (Broadwell), 8 GB de RAM, SSD Samsung 840 EVO 250 GB
- System2: Lenovo T440p, i5-4300M (Haswell), 16 GB de RAM, SSD Samsung 850 PRO 256 GB
- Distro / Kernel: Debian Jessie, 3.16.7
- cryptsetup: 1.6.6
/proc/crypto
para System1: http://pastebin.com/QUSGMfiScryptsetup benchmark
para System1: http://pastebin.com/4RxzPFeT- btrfs (-tools) é a versão 3.17
lsblk -t /dev/sdf
: http://pastebin.com/nv49tYWc
Pensamentos
- Alinhamento não é a causa, tanto quanto eu posso ver. Mesmo se o tamanho da página do stick for 16KiB, o início da carga útil da criptografia é alinhado a 2MiB de qualquer maneira.
--allow-discards
(para luksOpen do cryptsetup) não ajudou, como eu esperava.- Ao fazer muito menos experimentos com ele, observei um comportamento muito semelhante com um disco rígido externo, conectado através de um adaptador USB3.0.
- Parece-me que o sistema está escrevendo blocos de 64KiB. Um script de armadilha do sistema que tentei indica isso pelo menos.
/sys/block/sdf/stat
apoia essa hipótese, já que muitas gravações são mescladas. Então, meu palpite é que escrever em blocos muito pequenos não é a causa. - Não teve sorte alterar o agendador de filas do dispositivo de bloco para NOOP.
- Colocar a cripta em um volume LVM não ajudou.
fonte
Respostas:
A resposta (como agora eu sei): simultaneidade .
Resumindo : minha gravação sequencial , usando
dd
ou copiando um arquivo (como ... no uso diário), torna-se uma gravação pseudo-aleatória (incorreta) porque quatro threads estão trabalhando simultaneamente na gravação dos dados criptografados no dispositivo de bloco após a atualização simultânea. criptografia (boa).Mitigação (para kernels "mais antigos")
O efeito negativo pode ser mitigado aumentando a quantidade de solicitações na fila na fila do planejador de E / S assim:
No meu caso, isso quase triplica (~ 56 MB / s) a taxa de transferência para o teste de dados aleatórios de 4 GB explicado na minha pergunta. Obviamente, o desempenho ainda está aquém dos 100 MB / s em comparação com as E / S não criptografadas.
Investigação
Multicore
blktrace
Investiguei ainda o cenário problemático no qual um btrfs é colocado na parte superior de um dispositivo de bloco criptografado LUKS. Para me mostrar quais instruções de gravação são emitidas para o dispositivo de bloco real, usei
blktrace
assim:O que isso faz é (até onde eu pude compreender) rastrear a solicitação de E / S para o
/dev/sdc
tipo " write " e analisá-la na saída legível por humanos, mas restringir ainda mais a saída à ação " D ", que é (de acordo comman blkparse
) " IO emitido para o motorista ".O resultado foi algo como isto (consulte cerca de 5000 linhas de saída do log multicore ):
Este é um trecho da saída produzida ao
dd
inserir os dados aleatórios de 4 GB no sistema de arquivos montado. É claro que pelo menos dois processos estão envolvidos. O log restante mostra que os quatro processadores estão realmente trabalhando nele. Infelizmente, as solicitações de gravação não são mais solicitadas. Enquanto CPU0 está gravando em algum lugar no setor 38038416, a CPU1, que é agendada posteriormente, está gravando em algum lugar no setor 35713872. Isso é ruim.Único nucleo
blktrace
Fiz o mesmo experimento depois de desativar o multi-threading e desativar o segundo núcleo da minha CPU. Obviamente, apenas um processador está envolvido na gravação no stick. Mais importante, porém, a solicitação de gravação é adequadamente seqüencial, e é por isso que o desempenho total de gravação de ~ 170 MB / s é alcançado na mesma configuração.
Veja cerca de 5000 linhas de saída no log de singlecore .
Discussão
Agora que conheço a causa e os termos de pesquisa adequados do Google, as informações sobre esse problema estão subindo à superfície. Como se vê, não sou o primeiro a notar.
Corrigido nos kernels atuais (> = 4.0.2)
Como eu (mais tarde) achei o commit do kernel obviamente direcionado para esse problema exato, eu queria experimentar um kernel atualizado. [Depois de compilar e descobrir que já está dentro
debian/sid
] Acontece que o problema está realmente resolvido. Não sei a versão exata do kernel na qual a correção apareceu, mas o commit original fornecerá pistas para qualquer pessoa interessada.Para o registro:
Uma dica de chapéu para Mikulas Patocka, que foi o autor do commit.
fonte