糟糕的一般 dm-crypt (LUKS) 写入性能

sch*_*hen 24 performance dm-crypt btrfs luks cryptsetup

我正在调查一个问题,即加密块设备会在写入时造成巨大的性能损失。数小时的互联网阅读和实验并没有让我得到正确的理解,更不用说解决方案了。

简而言之:为什么将 btrfs 放到块设备上时我的写入速度非常快(~170MB/s),而将 dm-crypt/LUKS 放在块设备之间时写入速度会下降(~20MB/s)文件系统和块设备,尽管系统能够维持足够高的加密吞吐量?

设想

/home/schlimmchen/random是一个 4.0GB 的文件,里面装满了之前的数据/dev/urandom

dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096
Run Code Online (Sandbox Code Playgroud)

阅读速度超快:

$ 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
Run Code Online (Sandbox Code Playgroud)

(第二次,文件显然是从缓存中读取的)。

未加密的 btrfs

设备直接用btrfs格式化(块设备上没有分区表)。

$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
Run Code Online (Sandbox Code Playgroud)

写入速度高达 ~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
Run Code Online (Sandbox Code Playgroud)

读取速度远高于 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
Run Code Online (Sandbox Code Playgroud)

块设备上的加密 btrfs

设备用 LUKS 格式化,生成的设备用 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
Run Code Online (Sandbox Code Playgroud)

读取速度只受到轻微影响(为什么会这样?):

$ 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
Run Code Online (Sandbox Code Playgroud)

luksDump:http ://pastebin.com/i9VYRR0p

块设备上 btrfs 文件中的加密 btrfs

写入加密文件时,写入速度“飙升”至 150MB/s 以上。我把一个 btrfs 放到块设备上,分配了一个 16GB 的文件,我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
Run Code Online (Sandbox Code Playgroud)

为什么写性能会这样增长?这种文件系统和块设备的特殊嵌套对提高写入速度有什么帮助?

设置

该问题可在运行相同发行版和内核的两个系统上重现。但是,我还观察到 System2 上内核 3.19.0 的写入速度较低。

  • 设备:闪迪至尊 64GB USB3.0 U 盘
  • 系统 1:英特尔 NUC 5i5RYH、i5-5250U(Broadwell)、8GB RAM、三星 840 EVO 250GB SSD
  • 系统2:联想T440p、i5-4300M(Haswell)、16GB内存、三星850 PRO 256GB SSD
  • 发行版/内核:Debian Jessie,3.16.7
  • 密码设置:1.6.6
  • /proc/crypto系统 1:http : //pastebin.com/QUSGMfiS
  • cryptsetup benchmark系统 1:http : //pastebin.com/4RxzPFeT
  • btrfs(-tools) 是 3.17 版
  • lsblk -t /dev/sdfhttp : //pastebin.com/nv49tYWc

想法

  • 据我所知,对齐不是原因。即使棒的页面大小是 16KiB,cryptsetup 的有效负载开始也对齐到 2MiB。
  • --allow-discards (对于 cryptsetup 的 luksOpen)没有帮助,正如我所期望的。
  • 虽然用它做的实验少得多,但我观察到与通过 USB3.0 适配器连接的外部硬盘驱动器的行为非常相似。
  • 在我看来,系统正在写入 64KiB 块。我试过的一个systemtrap 脚本至少表明了这一点。/sys/block/sdf/stat由于合并了许多写入,因此支持该假设。所以我的猜测是写入太小的块不是原因。
  • 将块设备队列调度程序更改为 NOOP 并不走运。
  • 将 crypt 放入 LVM 卷没有帮助。

sch*_*hen 24

答案(正如我现在所知):并发

简而言之:我的顺序写入,无论是使用dd还是复制文件(例如......在日常使用中),都会变成伪随机写入(坏),因为四个线程同时工作,在并发后将加密数据写入块设备加密(好)。

缓解(针对“旧”内核)

可以通过增加 IO 调度程序队列中排队请求的数量来减轻负面影响,如下所示:

echo 4096 | sudo tee /sys/block/sdc/queue/nr_requests
Run Code Online (Sandbox Code Playgroud)

在我的情况下,这几乎是我的问题中解释的 4GB 随机数据测试的吞吐量的三倍(~56MB/s)。当然,与未加密的 IO 相比,性能仍然低于 100MB/s。

调查

多核 blktrace

我进一步研究了将 btrfs 放置在 LUKS 加密块设备顶部的问题场景。为了向我展示向实际块设备发出的写指令,我使用blktrace如下:

sudo blktrace -a write -d /dev/sdc -o - | blkparse -b 1 -i - | grep -w D
Run Code Online (Sandbox Code Playgroud)

这样做是(据我所知)跟踪/dev/sdc写入”类型的IO 请求,然后将其解析为人类可读的输出,但进一步将输出限制为操作“ D ”,即(根据man blkparse) “ IO 发给驱动程序”。

结果是这样的(参见多核日志的大约 5000 行输出):

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]
Run Code Online (Sandbox Code Playgroud)
  • 第 1 列:块设备的主要、次要
  • 第 2 列:CPU ID
  • 第 3 列:序列号
  • 第 4 列:时间戳
  • 第 5 列:进程 ID
  • 第 6 栏:行动
  • 第 7 列:RWBS 数据(类型、扇区、长度)

这是dd将 4GB 随机数据放入已安装的文件系统时产生的输出的片段。很明显,至少涉及两个过程。剩余的日志显示所有四个处理器实际上都在处理它。可悲的是,写入请求不再被排序。当 CPU0 在第 38038416 个扇区附近写入时,之后调度的 CPU1 则在第 35713872 个扇区附近写入。那很糟。

单核 blktrace

在禁用多线程并禁用我的 CPU 的第二个核心后,我做了同样的实验。当然,只有一个处理器参与写入棒。但更重要的是,写入请求是正确顺序的,这就是为什么在其他相同的设置中实现了约 170MB/s 的完整写入性能的原因。

查看单核日志大约 5000 行的输出

讨论

现在我知道了原因和正确的谷歌搜索词,关于这个问题的信息正在浮出水面。事实证明,我不是第一个注意到的人。

已在当前内核中修复 (>=4.0.2)

因为我(后来)发现内核提交显然是针对这个问题的,所以我想尝试一个更新的内核。【自己编译后发现已经在里面了debian/sid】原来问题确实解决了。我不知道修复出现的确切内核版本,但原始提交将为任何感兴趣的人提供线索。

作为记录:

$ 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
Run Code Online (Sandbox Code Playgroud)

给提交提交的 Mikulas Patocka 的帽子提示。

  • 三年后,我很确定我在 5.5.0 上遇到了这个问题。:( (2认同)