Problem
Niedawno zainstalowałem nowy dysk i utworzyłem na nim zpool:
/# zpool create morez /dev/sdb
Po dłuższym użyciu zauważyłem, że jest dość powolny:
/morez# fio --name rw --rw rw --size 10G
read: IOPS=19.6k, BW=76.6MiB/s (80.3MB/s)(5120MiB/66834msec)
write: IOPS=19.6k, BW=76.6MiB/s (80.3MB/s)(5120MiB/66834msec)
Ten test jest dość podobny do mojego faktycznego przypadku użycia. Czytam umiarkowaną liczbę (~ 10k) obrazów (~ 2 MiB każdy) z dysku. Zostały napisane od razu, gdy dysk był w większości pusty, więc nie oczekuję, że zostaną podzielone.
Dla porównania przetestowałem ext4:
/# gdisk /dev/sdb
...
/# mkfs.ext4 -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# fio --name rw --rw rw --size 10G
read: IOPS=48.3k, BW=189MiB/s (198MB/s)(5120MiB/27135msec)
write: IOPS=48.3k, BW=189MiB/s (198MB/s)(5120MiB/27135msec)
I btrfs:
/# mkfs.btrfs -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# fio --name rw --rw rw --size 10G
read: IOPS=51.3k, BW=201MiB/s (210MB/s)(5120MiB/25528msec)
write: IOPS=51.3k, BW=201MiB/s (210MB/s)(5120MiB/25528msec)
Co może powodować problemy z wydajnością ZFS i jak mogę to zrobić szybciej?
Nieudana próba rozwiązania
Próbowałem również jawnie ustawić rozmiar sektora dla zpool, ponieważ mój dysk ( Seagate ST1000DM003 ) używa 4096 bajtowych sektorów fizycznych:
/# zpool create -o ashift=12 morez /dev/sdb
Nie poprawiło to wydajności:
/morez# fio --name rw --rw rw --size 10G
read: IOPS=21.3k, BW=83.2MiB/s (87.2MB/s)(5120MiB/61573msec)
write: IOPS=21.3k, BW=83.2MiB/s (87.2MB/s)(5120MiB/61573msec)
Obserwacja
O dziwo, użycie Zvola miało świetną wydajność:
/# zfs create -V 20G morez/vol
/# fio --name rw --filename /dev/zvol/morez/vol --rw rw --size 10G
read: IOPS=52.7k, BW=206MiB/s (216MB/s)(5120MiB/24852msec)
write: IOPS=52.7k, BW=206MiB/s (216MB/s)(5120MiB/24852msec)
Dlaczego wpływa to tylko na systemy plików ZFS, a nie na Zvols?
Rozszerzone testowanie btrfs
W komentarzach zasugerowano, że różnica może wynikać z buforowania. Po dalszych testach nie sądzę, żeby tak było. Zwiększyłem rozmiar testu btrfs znacznie powyżej ilości pamięci, którą ma mój komputer, a jego wydajność była wciąż znacznie wyższa niż w przypadku ZFS:
/# mkfs.btrfs -f /dev/sdb1 && mount /dev/sdb1 /mnt && cd /mnt
/mnt# $ fio --name rw --rw rw --size 500G --runtime 3600 --time_based --ramp_time 900
read: IOPS=41.9k, BW=164MiB/s (172MB/s)(576GiB/3600003msec)
write: IOPS=41.9k, BW=164MiB/s (172MB/s)(576GiB/3600003msec)
Informacja o systemie
Oprogramowanie
- Arch Linux, wersja jądra 4.11.6
- ZFS w systemie Linux 0.6.5.10
- fio 2.21
Sprzęt komputerowy
- Testowany dysk: Seagate ST1000DM003 , podłączony do portu SATA 6 Gb / s
- Płyta główna: Gigabyte X99-SLI
- Pamięć: 8 GiB
Informacje o ZFS
Oto jak wyglądały właściwości ZFS przed uruchomieniem fio. Są to tylko wynik utworzenia zpool z domyślnymi ustawieniami.
# zpool get all morez
NAME PROPERTY VALUE SOURCE
morez size 928G -
morez capacity 0% -
morez altroot - default
morez health ONLINE -
morez guid [removed] default
morez version - default
morez bootfs - default
morez delegation on default
morez autoreplace off default
morez cachefile - default
morez failmode wait default
morez listsnapshots off default
morez autoexpand off default
morez dedupditto 0 default
morez dedupratio 1.00x -
morez free 928G -
morez allocated 276K -
morez readonly off -
morez ashift 0 default
morez comment - default
morez expandsize - -
morez freeing 0 default
morez fragmentation 0% -
morez leaked 0 default
morez feature@async_destroy enabled local
morez feature@empty_bpobj enabled local
morez feature@lz4_compress active local
morez feature@spacemap_histogram active local
morez feature@enabled_txg active local
morez feature@hole_birth active local
morez feature@extensible_dataset enabled local
morez feature@embedded_data active local
morez feature@bookmarks enabled local
morez feature@filesystem_limits enabled local
morez feature@large_blocks enabled local
# zfs get all morez
NAME PROPERTY VALUE SOURCE
morez type filesystem -
morez creation Thu Jun 29 19:34 2017 -
morez used 240K -
morez available 899G -
morez referenced 96K -
morez compressratio 1.00x -
morez mounted yes -
morez quota none default
morez reservation none default
morez recordsize 128K default
morez mountpoint /morez default
morez sharenfs off default
morez checksum on default
morez compression off default
morez atime on default
morez devices on default
morez exec on default
morez setuid on default
morez readonly off default
morez zoned off default
morez snapdir hidden default
morez aclinherit restricted default
morez canmount on default
morez xattr on default
morez copies 1 default
morez version 5 -
morez utf8only off -
morez normalization none -
morez casesensitivity sensitive -
morez vscan off default
morez nbmand off default
morez sharesmb off default
morez refquota none default
morez refreservation none default
morez primarycache all default
morez secondarycache all default
morez usedbysnapshots 0 -
morez usedbydataset 96K -
morez usedbychildren 144K -
morez usedbyrefreservation 0 -
morez logbias latency default
morez dedup off default
morez mlslabel none default
morez sync standard default
morez refcompressratio 1.00x -
morez written 96K -
morez logicalused 72.5K -
morez logicalreferenced 40K -
morez filesystem_limit none default
morez snapshot_limit none default
morez filesystem_count none default
morez snapshot_count none default
morez snapdev hidden default
morez acltype off default
morez context none default
morez fscontext none default
morez defcontext none default
morez rootcontext none default
morez relatime off default
morez redundant_metadata all default
morez overlay off default
źródło
/etc/modprobe.d/zfs.conf
man 5 zfs-module-parameters
.Odpowiedzi:
Choć jestem stary, uważam, że to pytanie zasługuje na odpowiedź.
fio
domyślnie wydaje IOP wielkości 4KB; Zamiast tego zestawy danych ZFS domyślnie używają opcji zapisu 128 KB. Ta niezgodność oznacza, że każdy zapis 4K powoduje odczyt / modyfikację / zapis całego rekordu 128K.ZVOL, z drugiej strony, domyślnie używają volblocksize 8K. Oznacza to, że zapis 4K powoduje znacznie mniejszy cykl odczytu / modyfikacji / zapisu rekordu 8K i przy odrobinie szczęścia dwa zapisy 4K można połączyć w jeden zapis 8K (który w ogóle nie wymaga odczytu / modyfikacji / zapisu).
zfs set recordize=8K <dataset>
Rozmiar rekordu zestawu danych ZFS można zmieniać za pomocą iw tym przypadku powinien on zapewniać mniej więcej równoważną wydajność niż ZVOL. Jednak w przypadku użycia do stosunkowo dużych transferów (OP mówił o 2 MB plikach, które jako obrazy powinny być w całości odczytywane przy każdym dostępie ), lepiej jest mieć duży rozmiar nagrania / volblocksize, czasem nawet większy niż ustawienie domyślne (128 KB).źródło
Uwaga: ponieważ brakuje zadania fio
direct=1
( http://fio.readthedocs.io/en/latest/fio_doc.html#cmdoption-arg-direct ), pewna ilość wykonywanych operacji we / wy (zarówno do odczytu, jak i do zapisu) może być buforowana przez system operacyjny, zniekształcając wyniki (i sztucznie zwiększając liczby). Samo to dodatkowo komplikuje:O_DIRECT
(więc otwarcie się nie udaje), albo jeśli tak, to cicho wraca do buforowanych operacji we / wy (patrz punkt 3 https://github.com/zfsonlinux/zfs/commit / a584ef26053065f486d46a7335bea222cb03eeea ).O_DIRECT
powrót do buforowanego wejścia / wyjścia.Należy pamiętać, że
O_DIRECT
nadal buforowanieO_DIRECT
operacji we / wy jest nadal dozwolone, ponieważ w systemie Linux jest to raczej wskazówka (zobacz sekcję referencji /programming//a/46377629/2732969 ).Jeśli znajdujesz się w sytuacji, w której nie możesz poprawnie ominąć pamięci podręcznej, bardzo ważne jest, aby zrobić wystarczająco dużo operacji we / wy na wystarczająco dużym obszarze, aby zminimalizować wpływ buforowania (chyba że rzeczywiście chcesz przetestować buforowanie) ...
źródło