Desempenho geral de gravação abismal de dm-crypt (LUKS)

16

Estou investigando um problema em que a criptografia de um dispositivo de bloco impõe uma penalidade de desempenho enorme ao escrever a ele. Horas de leitura e experiências na Internet não me proporcionaram um entendimento adequado, muito menos uma solução.

A questão em resumo: 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) quando colocando um dm-crypt / LUKS entre o sistema de arquivos e o dispositivo de bloco, embora o sistema seja mais do que capaz de sustentar um throughput de criptografia suficientemente alto?

Cenário

/home/schlimmchen/random é um arquivo de 4.0 GB preenchido com dados de /dev/urandom anterior.

dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096

Ler é 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

(a segunda vez, obviamente, o arquivo foi lido do cache).

btrfs não criptografados

O dispositivo é formatado diretamente com o btrfs (sem tabela de partições no dispositivo de bloco).

$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt

A velocidade de gravação aumenta até ~ 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 200MB / 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 é formatado com LUKS e o dispositivo resultante é 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 marginalmente (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: link

Btrfs criptografados no arquivo no btrfs no dispositivo de bloco

A velocidade de gravação "dispara" para mais de 150MB / s ao gravar em um arquivo criptografado. Eu coloquei um btrfs no dispositivo de bloco, alocou um arquivo de 16GB, que eu lukfsFormat ed e montado.

$ 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 particular de sistemas de arquivos e dispositivos de bloco consegue ajudar em altas velocidades de gravação?

Configuração

O problema é reproduzível em dois sistemas que executam a mesma distribuição e kernel. No entanto, também observei as baixas velocidades de gravação com o kernel 3.19.0 no System2.

  • Dispositivo: USB Memory Stick SanDisk Extreme 64 GB USB3.0
  • System1: Intel NUC 5i5RYH, i5-5250U (Broadwell), 8 GB de RAM, SSD Samsung 840 EVO de 250 GB
  • System2: Lenovo T440p, i5-4300M (Haswell), 16 GB de RAM, Samsung 850 PRO SSD de 256 GB
  • Distro / Kernel: Debian Jessie, 3.16.7
  • cryptsetup: 1.6.6
  • /proc/crypto para o System1: link
  • cryptsetup benchmark para o System1: link
  • btrfs (-tools) é a versão 3.17
  • lsblk -t /dev/sdf : link

Pensamentos

  • O alinhamento é não a causa até onde eu posso ver. Mesmo se o tamanho da página do bastão for 16KiB, a carga útil da cryptsetup será alinhada para 2MiB de qualquer maneira.
  • --allow-discards (para o 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 por meio de um adaptador USB3.0.
  • Parece-me que o sistema está escrevendo blocos de 64 KiB. Um script systemtrap Eu tentei indica que pelo menos. /sys/block/sdf/stat faz o backup dessa hipótese, já que muitas gravações são mescladas. Então, meu palpite é que escrever em blocos muito pequenos não é a causa.
  • Sem sorte com a alteração do agendador de fila de dispositivos de bloco para NOOP.
  • Colocar a cripta em um volume LVM não ajudou.
por schlimmchen 15.05.2015 / 21:41

1 resposta

13

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.

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.

    
por 16.05.2015 / 12:42