Estoy investigando un problema en el que cifrar un dispositivo de bloque impone una gran penalización de rendimiento al escribir en él. Horas de lectura y experimentos en Internet no me proporcionaron una comprensión adecuada, y mucho menos una solución.
La pregunta en resumen: ¿por qué obtengo velocidades de escritura perfectamente rápidas cuando pongo un btrfs en un dispositivo de bloque (~ 170MB / s), mientras que la velocidad de escritura cae en picada (~ 20MB / s) cuando pongo un dm-crypt / LUKS entre sistema de archivos y el dispositivo de bloque, aunque el sistema es más que capaz de mantener un rendimiento de cifrado suficientemente alto?
Guión
/home/schlimmchen/random
es un archivo de 4.0GB lleno de datos de /dev/urandom
antes.
dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096
Leerlo es súper 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
(la segunda vez, el archivo obviamente se leyó del caché).
Btrfs sin cifrar
El dispositivo está formateado directamente con btrfs (sin tabla de particiones en el dispositivo de bloque).
$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
La velocidad de escritura llega a ~ 170 MB / 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
La velocidad de lectura está muy por encima 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 cifrados en el dispositivo de bloque
El dispositivo está formateado con LUKS, y el dispositivo resultante está formateado con 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
La velocidad de lectura sufre solo marginalmente (¿por qué lo hace en absoluto?):
$ 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 cifrados en el archivo en btrfs en el dispositivo de bloque
La velocidad de escritura "se dispara" a más de 150 MB / s cuando se escribe en un archivo cifrado. Puse un btrfs en el dispositivo de bloque, asigné un archivo de 16GB, que edité y monté lukfsFormat
.
$ 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 qué aumenta el rendimiento de escritura de esta manera? ¿Qué logra este anidamiento particular de sistemas de archivos y dispositivos de bloque para ayudar en altas velocidades de escritura?
Preparar
El problema es reproducible en dos sistemas que ejecutan la misma distribución y kernel. Sin embargo, también observé las bajas velocidades de escritura con el kernel 3.19.0 en System2.
- Dispositivo: SanDisk Extreme 64GB USB3.0 USB Stick
- Sistema1: Intel NUC 5i5RYH, i5-5250U (Broadwell), 8GB RAM, Samsung 840 EVO 250GB SSD
- Sistema2: Lenovo T440p, i5-4300M (Haswell), 16GB RAM, Samsung 850 PRO 256GB SSD
- 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) es la versión 3.17
lsblk -t /dev/sdf
: http://pastebin.com/nv49tYWc
Pensamientos
- La alineación no es la causa por lo que puedo ver. Incluso si el tamaño de página del dispositivo es de 16 KB, el inicio de la carga útil de cryptsetup está alineado a 2 Mb de todos modos.
--allow-discards
(para crykssetup's luksOpen) no ayudó, como esperaba.- Mientras hacía muchos menos experimentos con él, observé un comportamiento muy similar con un disco duro externo, conectado a través de un adaptador USB3.0.
- Me parece que el sistema está escribiendo bloques de 64 KB. Un script de systemtrap que probé indica que al menos eso.
/sys/block/sdf/stat
respalda esta hipótesis, ya que muchas escrituras se fusionan. Entonces, supongo que escribir en bloques demasiado pequeños no es la causa. - No hubo suerte con cambiar el planificador de la cola del dispositivo de bloque a NOOP.
- Poner la cripta en un volumen LVM no ayudó.
fuente
Respuestas:
La respuesta (como ahora sé): concurrencia .
En resumen : mi escritura secuencial , ya sea usando
dd
o al copiar un archivo (como ... en uso diario), se convierte en una escritura pseudoaleatoria (mala) porque cuatro hilos están trabajando simultáneamente para escribir los datos cifrados en el dispositivo de bloque después de concurrente cifrado (bueno).Mitigación (para núcleos "antiguos")
El efecto negativo puede mitigarse aumentando la cantidad de solicitudes en cola en la cola del planificador de E / S de esta manera:
En mi caso, esto casi se triplica (~ 56MB / s) el rendimiento para la prueba de datos aleatorios de 4GB explicada en mi pregunta. Por supuesto, el rendimiento aún se queda corto de 100 MB / s en comparación con IO sin cifrar.
Investigación
Multinúcleo
blktrace
Investigué aún más el escenario problemático en el que se coloca un btrfs en la parte superior de un dispositivo de bloque cifrado LUKS. Para mostrarme qué instrucciones de escritura se emiten al dispositivo de bloqueo real, utilicé
blktrace
así:Lo que esto hace es (por lo que pude comprender) rastrear la solicitud de E / S a la
/dev/sdc
que son de tipo " escribir ", luego analizar esto a salida legible por humanos pero restringir aún más la salida a la acción " D ", que es (segúnman blkparse
) " IO emitido al conductor ".El resultado fue algo como esto (ver aproximadamente 5000 líneas de salida del registro multinúcleo ):
Esto es un recorte de la salida producida al
dd
incorporar los datos aleatorios de 4GB en el sistema de archivos montado. Está claro que al menos dos procesos están involucrados. El registro restante muestra que los cuatro procesadores realmente están trabajando en él. Lamentablemente, las solicitudes de escritura ya no se ordenan. Mientras CPU0 escribe en algún lugar alrededor del sector 38038416, CPU1, que está programado después, escribe en algún lugar alrededor del sector 35713872. Eso es malo.Núcleo simple
blktrace
Hice el mismo experimento después de deshabilitar subprocesos múltiples y deshabilitar el segundo núcleo de mi CPU. Por supuesto, solo un procesador participa en la escritura en el dispositivo. Pero lo que es más importante, la solicitud de escritura es propiamente secuencial, por lo que el rendimiento completo de escritura de ~ 170 MB / s se logra en la misma configuración.
Eche un vistazo a aproximadamente 5000 líneas de salida en el registro de un solo núcleo .
Discusión
Ahora que conozco la causa y los términos de búsqueda de Google adecuados, la información sobre este problema está surgiendo a la superficie. Resulta que no soy el primero en notarlo.
Corregido en los núcleos actuales (> = 4.0.2)
Como (más tarde) encontré que la confirmación del kernel obviamente estaba dirigida a este problema exacto, quería probar un kernel actualizado. [Después de compilarlo yo mismo y luego descubrir que ya está en
debian/sid
] Resulta que el problema está solucionado. No sé la versión exacta del núcleo en la que apareció la corrección, pero la confirmación original dará pistas a cualquier persona interesada.Para el registro:
Una punta de sombrero para Mikulas Patocka, quien escribió el commit.
fuente