J'étudie un problème où le cryptage d'un périphérique de bloc impose une énorme pénalité de performance lors de l' écriture . Des heures de lecture et d'expériences sur Internet ne m'ont pas permis de bien comprendre, encore moins de trouver une solution.
La question en bref: pourquoi est-ce que j'obtiens des vitesses d'écriture parfaitement rapides lorsque je place un btrfs sur un périphérique de bloc (~ 170 Mo / s), alors que la vitesse d'écriture chute (~ 20 Mo / s) lorsque je place un dm-crypt / LUKS entre les système de fichiers et le périphérique de bloc, bien que le système soit plus que capable de maintenir un débit de cryptage suffisamment élevé?
Scénario
/home/schlimmchen/random
est un fichier de 4,0 Go rempli de données /dev/urandom
antérieures.
dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096
La lecture est super rapide:
$ 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 deuxième fois, le fichier a évidemment été lu dans le cache).
Btrfs non chiffrés
Le périphérique est directement formaté avec btrfs (pas de table de partition sur le périphérique bloc).
$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
La vitesse d'écriture atteint ~ 170 Mo / 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 vitesse de lecture est bien supérieure à 200 Mo / 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 chiffrés sur périphérique bloc
Le périphérique est formaté avec LUKS et le périphérique résultant est formaté avec 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 vitesse de lecture ne souffre que marginalement (pourquoi le fait-elle?):
$ 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 chiffrés dans un fichier sur btrfs sur un périphérique bloc
La vitesse d'écriture "monte en flèche" à plus de 150 Mo / s lors de l'écriture dans un fichier crypté. J'ai mis un btrfs sur le périphérique bloc, alloué un fichier de 16 Go, que j'ai lukfsFormat
édité et monté.
$ 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
Pourquoi les performances d'écriture augmentent-elles ainsi? Qu'est-ce que cette imbrication particulière de systèmes de fichiers et de périphériques de blocs permet d'obtenir à des vitesses d'écriture élevées?
Installer
Le problème est reproductible sur deux systèmes exécutant la même distribution et le même noyau. Cependant, j'ai également observé les faibles vitesses d'écriture avec le noyau 3.19.0 sur System2.
- Périphérique: clé USB SanDisk Extreme 64 Go USB 3.0
- System1: Intel NUC 5i5RYH, i5-5250U (Broadwell), 8 Go de RAM, Samsung 840 EVO 250 Go SSD
- System2: Lenovo T440p, i5-4300M (Haswell), 16 Go de RAM, Samsung 850 PRO 256 Go SSD
- Distro / Kernel: Debian Jessie, 3.16.7
- cryptsetup: 1.6.6
/proc/crypto
pour System1: http://pastebin.com/QUSGMfiScryptsetup benchmark
pour System1: http://pastebin.com/4RxzPFeT- btrfs (-tools) est la version 3.17
lsblk -t /dev/sdf
: http://pastebin.com/nv49tYWc
Pensées
- L'alignement n'est pas la cause pour autant que je puisse voir. Même si la taille de page de la clé est de 16 Ko, le début de la charge utile de cryptsetup est de toute façon aligné sur 2 Mo.
--allow-discards
(pour luksOpen de cryptsetup) n'a pas aidé, comme je m'y attendais.- En faisant beaucoup moins d'expériences avec lui, j'ai observé un comportement très similaire avec un disque dur externe, connecté via un adaptateur USB3.0.
- Il me semble que le système écrit des blocs de 64 Ko. Un script systemtrap que j'ai essayé indique au moins cela.
/sys/block/sdf/stat
soutient cette hypothèse car de nombreuses écritures sont fusionnées. Donc, je suppose que l'écriture dans des blocs trop petits n'est pas la cause. - Pas de chance de changer le planificateur de file d'attente de périphérique de bloc en NOOP.
- Mettre la crypte dans un volume LVM n'a pas aidé.
la source
Réponses:
La réponse (comme je le sais maintenant): la concurrence .
En bref : mon écriture séquentielle , en utilisant
dd
ou lors de la copie d'un fichier (comme ... dans une utilisation quotidienne), devient une écriture pseudo-aléatoire (mauvaise) car quatre threads travaillent simultanément sur l'écriture des données chiffrées sur le périphérique de bloc après simultané cryptage (bon).Atténuation (pour les noyaux "plus anciens")
L'effet négatif peut être atténué en augmentant le nombre de demandes en file d'attente dans la file d'attente du planificateur d'E / S comme suit:
Dans mon cas, cela triple presque (~ 56 Mo / s) le débit pour le test de données aléatoires de 4 Go expliqué dans ma question. Bien sûr, les performances sont toujours inférieures à 100 Mo / s par rapport aux E / S non chiffrées.
Enquête
Multicore
blktrace
J'ai en outre étudié le scénario problématique dans lequel un btrfs est placé sur le dessus d'un périphérique de bloc crypté LUKS. Pour me montrer quelles instructions d'écriture sont envoyées au périphérique de bloc réel, j'ai utilisé
blktrace
comme ceci:Ce que cela fait (pour autant que je puisse comprendre) trace les demandes d'E / S
/dev/sdc
auxquelles sont de type " écriture ", puis analyse ceci sur une sortie lisible par l'homme mais restreint davantage la sortie à l'action " D ", qui est (selonman blkparse
) " IO délivré au conducteur ".Le résultat était quelque chose comme ça (voir environ 5000 lignes de sortie du journal multicœur ):
Il s'agit d'un extrait de la sortie produite pendant
dd
le chargement des données aléatoires de 4 Go sur le système de fichiers monté. Il est clair qu'au moins deux processus sont impliqués. Le journal restant montre que les quatre processeurs y travaillent réellement. Malheureusement, les demandes d'écriture ne sont plus ordonnées. Alors que CPU0 écrit quelque part autour du secteur 38038416th, CPU1, qui est prévu par la suite, écrit quelque part autour du secteur 35713872nd. C'est mauvais.Singlecore
blktrace
J'ai fait la même expérience après avoir désactivé le multithread et désactivé le deuxième cœur de mon processeur. Bien sûr, un seul processeur est impliqué dans l'écriture sur la clé. Mais plus important encore, les demandes d'écriture sont correctement séquentielles, c'est pourquoi les performances d'écriture complètes de ~ 170 Mo / s sont obtenues dans la même configuration.
Jetez un œil à environ 5 000 lignes de sortie dans le journal à un seul cœur .
Discussion
Maintenant que je connais la cause et les termes de recherche google appropriés, les informations sur ce problème remontent à la surface. Il s'avère que je ne suis pas le premier à le remarquer.
Corrigé dans les noyaux actuels (> = 4.0.2)
Parce que j'ai (plus tard) trouvé que la validation du noyau visait visiblement ce problème précis, je voulais essayer un noyau mis à jour. [Après l'avoir compilé moi-même et avoir découvert qu'il est déjà dedans
debian/sid
] Il s'avère que le problème est en effet résolu. Je ne connais pas la version exacte du noyau dans laquelle le correctif est apparu, mais le commit d'origine donnera des indices à toute personne intéressée.Pour mémoire:
Un petit chapeau à Mikulas Patocka, qui est l'auteur du commit.
la source