糟糕的通用 dm-crypt (LUKS) 寫入性能
我正在調查一個問題,即加密塊設備在寫入時會造成****巨大的性能損失。數小時的網際網路閱讀和實驗並沒有為我提供正確的理解,更不用說解決方案了。
**簡而言之:**為什麼將 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
閱讀速度超級快:
$ 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
(第二次,文件顯然是從記憶體中讀取的)。
未加密的 btrfs
設備直接用 btrfs 格式化(塊設備上沒有分區表)。
$ sudo mkfs.btrfs /dev/sdf $ sudo mount /dev/sdf /mnt $ sudo chmod 777 /mnt
寫入速度高達 ~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
讀取速度遠高於 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
設備用 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
讀取速度只受到輕微影響(為什麼會這樣?):
$ 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 文件中的加密 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
為什麼寫入性能會這樣提高?文件系統和塊設備的這種特殊嵌套對提高寫入速度有什麼幫助?
設置
在執行相同發行版和核心的兩個系統上可以重現該問題。但是,我還觀察到 System2 上核心 3.19.0 的低寫入速度。
- 設備:閃迪至尊 64GB USB3.0 USB 記憶棒
- 系統 1:英特爾 NUC 5i5RYH、i5-5250U (Broadwell)、8GB RAM、三星 840 EVO 250GB SSD
- System2:聯想 T440p、i5-4300M (Haswell)、16GB RAM、三星 850 PRO 256GB SSD
- 發行版/核心:Debian Jessie,3.16.7
- 密碼設置:1.6.6
/proc/crypto
對於系統 1:http: //pastebin.com/QUSGMfiScryptsetup benchmark
對於系統 1:http: //pastebin.com/4RxzPFeT- btrfs(-tools) 是 3.17 版
lsblk -t /dev/sdf
: http://pastebin.com/nv49tYWc想法
- 據我所知,對齊不是原因。即使儲存棒的頁面大小為 16KiB,cryptsetup 有效負載的開始也始終與 2MiB 對齊。
--allow-discards
(對於 cryptsetup 的 luksOpen)沒有幫助,正如我所料。- 雖然用它做的實驗少得多,但我觀察到通過 USB3.0 適配器連接的外部硬碟驅動器的行為非常相似。
- 在我看來,系統正在寫入 64KiB 塊。我試過的一個系統陷阱腳本至少表明了這一點。
/sys/block/sdf/stat
支持這個假設,因為很多寫入被合併。所以我的猜測是寫太小塊不是原因。- 將塊設備隊列調度程序更改為 NOOP 可不行。
- 將 crypt 放入 LVM 卷沒有幫助。
答案(據我所知):並發。
簡而言之:我的順序寫入,無論是使用
dd
還是在復製文件時(例如…在日常使用中),都變成了偽隨機寫入(壞),因為四個執行緒在並發後同時將加密數據寫入塊設備加密(好)。緩解(對於“舊”核心)
可以通過增加 IO 調度程序隊列中的排隊請求數量來減輕負面影響,如下所示:
echo 4096 | sudo tee /sys/block/sdc/queue/nr_requests
在我的情況下,這幾乎是我的問題中解釋的 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
這樣做是(據我所知)跟踪
/dev/sdc
類型為“ write ”的 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]
- 第1列:塊設備的主要,次要
- 第 2 列:CPU ID
- 第 3 列:序列號
- 第 4 列:時間戳
- 第 5 列:程序 ID
- 第 6 欄:行動
- 第 7 列:RWBS 數據(類型、扇區、長度)
這是
dd
將 4GB 隨機數據寫入已掛載的文件系統時產生的輸出的片段。顯然,至少涉及兩個過程。剩下的日誌顯示所有四個處理器實際上都在處理它。可悲的是,不再對寫入請求進行排序。當 CPU0 在第 38038416 扇區附近寫入時,稍後安排的 CPU1 正在在第 35713872 扇區附近寫入。那很糟。單核
blktrace
在禁用多執行緒並禁用 CPU 的第二個核心後,我做了同樣的實驗。當然,只有一個處理器參與寫入記憶棒。但更重要的是,寫入請求是正確順序的,這就是為什麼在其他相同的設置中可以實現 ~170MB/s 的完整寫入性能。
討論
既然我知道了原因和正確的Google搜尋詞,關於這個問題的資訊就會浮出水面。事實證明,我不是第一個注意到的人。
- 四年前,一個更新檔為核心帶來了多執行緒 dm-crypt 。該送出幾乎完全符合我的發現。
- 兩年前,討論了更新檔以提高 dm-crypt 性能,包括重新排序寫入請求。
- 一年前,這個話題還在討論。
- 最近,一個為 dm-crypt 啟用排序的更新檔終於送出給了核心。
- 有一封有趣的電子郵件,其中包含有關此現象的性能測試(我沒有閱讀太多)。
在目前核心中修復 (>=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
向送出送出的 Mikulas Patocka 致敬。