Badam problem polegający na tym, że szyfrowanie urządzenia blokowego nakłada ogromną obniżkę wydajności podczas pisania na nim. Godziny czytania w Internecie i eksperymenty nie zapewniły mi właściwego zrozumienia, nie mówiąc już o rozwiązaniu.
Pytanie w skrócie: Dlaczego uzyskuję idealnie duże prędkości zapisu, gdy umieszczam btrfs na urządzeniu blokowym (~ 170 MB / s), podczas gdy prędkość zapisu spada (~ 20 MB / s), gdy umieszczamy dm-crypt / LUKS pomiędzy system plików i urządzenie blokujące, chociaż system jest w stanie utrzymać wystarczająco wysoką przepustowość szyfrowania?
Scenariusz
/home/schlimmchen/random
to plik 4,0 GB wypełniony /dev/urandom
wcześniejszymi danymi .
dd if=/dev/urandom of=/home/schlimmchen/Documents/random bs=1M count=4096
Czytanie jest bardzo szybkie:
$ 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
(po raz drugi plik został oczywiście odczytany z pamięci podręcznej).
Nieszyfrowane btrfs
Urządzenie jest bezpośrednio formatowane przy pomocy btrfs (brak tablicy partycji na urządzeniu blokowym).
$ sudo mkfs.btrfs /dev/sdf
$ sudo mount /dev/sdf /mnt
$ sudo chmod 777 /mnt
Prędkość zapisu osiąga nawet ~ 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
Szybkość odczytu jest znacznie powyżej 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
Zaszyfrowane btrfs na urządzeniu blokowym
Urządzenie jest sformatowane za pomocą LUKS, a powstałe urządzenie jest sformatowane za pomocą 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
Prędkość odczytu cierpi tylko nieznacznie (dlaczego w ogóle?):
$ 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
Zaszyfrowane pliki btrfs w pliku na btrfs na urządzeniu blokowym
Prędkość zapisu „gwałtownie rośnie” do ponad 150 MB / s przy zapisie do zaszyfrowanego pliku. Umieściłem btrfs na urządzeniu blokowym, przydzieliłem plik 16 GB, który lukfsFormat
zredagowałem i zamontowałem.
$ 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
Dlaczego wydajność zapisu rośnie w ten sposób? Co osiąga to szczególne zagnieżdżanie systemów plików i urządzeń blokowych, aby pomóc w wysokich prędkościach zapisu?
Ustawiać
Problem można odtworzyć w dwóch systemach z tą samą dystrybucją i jądrem. Jednak zaobserwowałem również niskie prędkości zapisu w jądrze 3.19.0 na System2.
- Urządzenie: pamięć USB SanDisk Extreme 64 GB USB 3.0
- System1: Intel NUC 5i5RYH, i5-5250U (Broadwell), 8 GB pamięci RAM, Samsung 840 EVO 250 GB SSD
- System2: Lenovo T440p, i5-4300M (Haswell), 16 GB pamięci RAM, Samsung 850 PRO 256 GB SSD
- Distro / Kernel: Debian Jessie, 3.16.7
- cryptsetup: 1.6.6
/proc/crypto
dla System1: http://pastebin.com/QUSGMfiScryptsetup benchmark
dla System1: http://pastebin.com/4RxzPFeT- btrfs (-tools) to wersja 3.17
lsblk -t /dev/sdf
: http://pastebin.com/nv49tYWc
Myśli
- O ile wiem, wyrównanie nie jest przyczyną. Nawet jeśli rozmiar strony kija wynosi 16 kB, początkowy ładunek szyfrowania jest i tak wyrównany do 2 MB.
--allow-discards
(dla luksOpen cryptsetup) nie pomogło, jak się spodziewałem.- Robiąc z nim o wiele mniej eksperymentów, zaobserwowałem bardzo podobne zachowanie z zewnętrznym dyskiem twardym podłączonym przez adapter USB 3.0.
- Wydaje mi się, że system zapisuje bloki 64 KB. Skrypt systemtrap Próbowałem wskazuje, że przynajmniej.
/sys/block/sdf/stat
popiera tę hipotezę, ponieważ wiele zapisów jest scalonych. Domyślam się więc, że pisanie zbyt małymi blokami nie jest przyczyną. - Brak powodzenia w zmianie harmonogramu kolejki urządzeń blokowych na NOOP.
- Umieszczenie krypty w woluminie LVM nie pomogło.
źródło
Odpowiedzi:
Odpowiedź (jak teraz wiem): współbieżność .
W skrócie : Mój sekwencyjny zapis , przy użyciu
dd
lub podczas kopiowania pliku (jak ... w codziennym użyciu), staje się pseudolosowym zapisem (zły), ponieważ cztery wątki pracują jednocześnie przy zapisie zaszyfrowanych danych na urządzeniu blokowym po równoczesnym szyfrowanie (dobre).Łagodzenie (dla „starszych” jąder)
Negatywny efekt można złagodzić, zwiększając liczbę żądań w kolejce w kolejce harmonogramu We / Wy w następujący sposób:
W moim przypadku prawie trzykrotnie (~ 56 MB / s) przepustowość losowego testu danych 4 GB wyjaśniona w moim pytaniu. Oczywiście wydajność wciąż nie przekracza 100 MB / s w porównaniu do nieszyfrowanego IO.
Dochodzenie
Wielordzeniowy
blktrace
Dalej zbadałem problematyczny scenariusz, w którym btrfs jest umieszczony na górze urządzenia blokowego szyfrowanego LUKS. Aby pokazać mi, jakie instrukcje zapisu są wysyłane do rzeczywistego urządzenia blokowego, użyłem
blktrace
tego w następujący sposób:To, co robi, to (o ile mogłem to zrozumieć) śledzić żądanie We / Wy, do
/dev/sdc
którego są typu „ zapisz ”, a następnie parsować je do danych wyjściowych czytelnych dla ludzi, ale dodatkowo ograniczyć dane wyjściowe do działania „ D ”, które jest (zgodnie zman blkparse
) „ IO wydane kierowcy ”.Wynik był mniej więcej taki (patrz około 5000 wierszy danych wyjściowych dziennika wielordzeniowego ):
Jest to wycinek danych wyjściowych wygenerowanych podczas
dd
zapisywania losowych danych 4 GB na zamontowanym systemie plików. Oczywiste jest, że w grę wchodzą co najmniej dwa procesy. Pozostały dziennik pokazuje, że wszystkie cztery procesory faktycznie nad nim pracują. Niestety, prośby o zapis nie są już zamawiane. Podczas gdy CPU0 pisze gdzieś w okolicach 38038416. sektora, CPU1, który jest zaplanowany później, pisze gdzieś w okolicach 35713872. sektora. To źle.Pojedynczy rdzeń
blktrace
Zrobiłem ten sam eksperyment po wyłączeniu wielowątkowości i wyłączeniu drugiego rdzenia mojego procesora. Oczywiście tylko jeden procesor jest zaangażowany w pisanie na patyku. Co ważniejsze, żądanie zapisu jest odpowiednio sekwencyjne, dlatego pełną wydajność zapisu ~ 170 MB / s uzyskuje się w tej samej konfiguracji.
Spójrz na około 5000 wierszy danych wyjściowych w dzienniku singlecore .
Dyskusja
Teraz, gdy znam przyczynę i odpowiednie wyszukiwane hasła w Google, informacje o tym problemie pojawiają się na powierzchni. Jak się okazuje, nie jestem pierwszym, który to zauważa.
Naprawiono w obecnych jądrach (> = 4.0.2)
Ponieważ (później) odkryłem, że zatwierdzenie jądra jest wyraźnie ukierunkowane na ten właśnie problem, chciałem wypróbować zaktualizowane jądro. [Po samodzielnym skompilowaniu i odkryciu, że już jest w środku
debian/sid
] Okazuje się, że problem rzeczywiście został rozwiązany. Nie znam dokładnej wersji jądra, w której pojawiła się poprawka, ale oryginalne zatwierdzenie da wskazówki wszystkim zainteresowanym.Dla przypomnienia:
Czapka dla Mikulasa Patockiego, który jest autorem commitu.
źródło