Abysmal general dm-crypt (LUKS) write performance

21

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/urandomanteriores.

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 lukfsFormatmontei 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/cryptopara System1: http://pastebin.com/QUSGMfiS
  • cryptsetup benchmarkpara 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/statapoia 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.
Schlimmchen
fonte
Limpar o cache de disco antes de cada teste seria eliminá-lo como uma possível razão para a velocidade (648MB / s sons inatingível atualmente, fora da ram)
Xen2050

Respostas:

18

A resposta (como agora eu sei): simultaneidade .

Resumindo : minha gravação sequencial , usando ddou 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:

echo 4096 | sudo tee /sys/block/sdc/queue/nr_requests

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 blktraceassim:

sudo blktrace -a write -d /dev/sdc -o - | blkparse -b 1 -i - | grep -w D

O que isso faz é (até onde eu pude compreender) rastrear a solicitação de E / S para o /dev/sdctipo " write " e analisá-la na saída legível por humanos, mas restringir ainda mais a saída à ação " D ", que é (de acordo com man blkparse) " IO emitido para o motorista ".

O resultado foi algo como isto (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: principal, menor do dispositivo de bloco
  • Coluna 2: ID da CPU
  • Coluna 3: número de sequência
  • Coluna 4: registro de data e hora
  • Coluna 5: ID do processo
  • Coluna 6: ação
  • Coluna 7: dados RWBS (tipo, setor, comprimento)

Este é um trecho da saída produzida ao ddinserir 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:

$ 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 de chapéu para Mikulas Patocka, que foi o autor do commit.

Schlimmchen
fonte
1
Estou usando o btrfs no luks com o kernel 4.12.12 e a lentidão ainda está lá!
brauliobo
por que você diz que a desaceleração ainda está lá? que referência você está usando para não sofrer uma desaceleração? qual é a sua configuração? você verificou o desempenho da unidade ao remover apenas o LUKS?
schlimmchen
confirmou que ainda está relacionado com LUKS unix.stackexchange.com/a/393521/39985
brauliobo
1
Agora entendo por que você escreveria sobre ainda experimentando uma "desaceleração". No entanto, seu problema está meramente relacionado a esse, definitivamente não é o mesmo problema (atraso versus baixo desempenho). Eu também experimento esses hickups irritantes, por isso estou muito agradecido por você ter apontado seu problema aqui! Não usar LUKS não é uma opção, mas é bom saber que parece estar relacionado à causa.
schlimmchen 22/09