
Na wiosnę omówiliśmy już kilka wprowadzających tematów, takich jak i . W drugim z nich obiecaliśmy nawet kontynuować badanie wydajności różnych topologii wielodyskowych w ZFS. To system plików nowej generacji, który obecnie wdrażany jest wszędzie: od do .
Cóż, dzisiaj jest najlepszy dzień, aby poznać ZFS, drodzy czytelnicy. Po prostu pamiętajcie, że według skromnej oceny twórcy OpenZFS, Matta Arenza, „to naprawdę skomplikowane”.
Ale zanim przejdziemy do liczb — a te będą, obiecuję — dotyczących wszystkich opcji ośmiodyskowej konfiguracji ZFS, trzeba porozmawiać o tym, jak jak ZFS operuje na danych na dysku.
Zpool, vdev i device

Ta diagram przedstawia pełny pul z trzema pomocniczymi vdevami, po jednym z każdego rodzaju, oraz czterema dla RAIDz2

Zwykle nie ma powodów, aby tworzyć pul z niezgodnych typów i rozmiarów vdev – ale jeśli chcesz, nic nie stoi na przeszkodzie, aby to zrobić
Aby naprawdę zrozumieć system plików ZFS, musisz dokładnie przyjrzeć się jego rzeczywistej strukturze. Po pierwsze, ZFS łączy tradycyjne poziomy zarządzania wolumenami i systemem plików. Po drugie, stosuje transakcyjny mechanizm kopiowania przy zapisie. Te cechy oznaczają, że system strukturalnie różni się bardzo od zwykłych systemów plików i macierzy RAID. Pierwszym zestawem podstawowych budulców do zrozumienia jest: pul storage (zpool), wirtualne urządzenie (vdev) i rzeczywiste urządzenie (device).
zpool
Pul storage zpool to najwyższa struktura ZFS. Każdy pul zawiera jedno lub więcej wirtualnych urządzeń. Z kolei każde z nich zawiera jedno lub więcej rzeczywistych urządzeń (device). Wirtualne pule to autonomiczne bloki. Jeden fizyczny komputer może zawierać dwa lub więcej oddzielnych pułków, ale każdy jest całkowicie niezależny od innych. Puli nie mogą współdzielić wirtualnych urządzeń.
Nadwyżka ZFS występuje na poziomie wirtualnych urządzeń, a nie na poziomie pułów. Na poziomie pułów nie ma absolutnie żadnej nadwyżki — jeśli którekolwiek urządzenie vdev lub specjalne vdev zostanie utracone, cały pul zostanie utracony.
Nowoczesne pule storage mogą przetrwać utratę pamięci podręcznej lub dziennika urządzenia wirtualnego — chociaż mogą stracić niewielką ilość nieczystych danych, jeśli utracą dziennik vdev podczas awarii zasilania lub systemu.
Panuje powszechne nieporozumienie, że „pasy danych” (stripy) ZFS są zapisywane w całej puli. To nieprawda. Zpool to wcale nie ciekawy RAID0, to raczej coś bardziej interesującego. złożonym zmiennym mechanizmem dystrybucji.
W większości przypadków zapisy są rozkładane między dostępne urządzenia wirtualne w zależności od dostępnej przestrzeni, tak że teoretycznie wszystkie będą napełniane równocześnie. W późniejszych wersjach ZFS uwzględniono bieżące wykorzystanie (utilizację) vdev — jeśli jedno urządzenie wirtualne jest znacznie bardziej obciążone niż inne (na przykład z powodu obciążenia podczas odczytu), zostanie tymczasowo pominięte przy zapisie, mimo że ma najwyższy współczynnik dostępnej przestrzeni.
Mechanizm określania wykorzystania wbudowany w nowoczesne metody dystrybucji zapisów ZFS może zmniejszyć opóźnienia i zwiększyć przepustowość w okresach nietypowo wysokiego obciążenia — ale to nie dawanie carte blanche na niezamierzone mieszanie wolnych HDD i szybkich SSD w jednej puli. Taka nierówna pula będzie nadal pracować z prędkością najwolniejszego urządzenia, jak gdyby była całkowicie złożona z takich urządzeń.
vdev
Każda pula storage składa się z jednego lub kilku urządzeń wirtualnych (virtual device, vdev). Z kolei każde vdev zawiera jedno lub kilka rzeczywistych urządzeń. Większość urządzeń wirtualnych jest używana do prostego przechowywania danych, ale istnieje kilka pomocniczych klas vdev, w tym CACHE, LOG i SPECIAL. Każdy z tych typów vdev może mieć jedną z pięciu topologii: urządzenie pojedyncze (single-device), RAIDz1, RAIDz2, RAIDz3 lub lustro (mirror).
RAIDz1, RAIDz2 i RAIDz3 to specjalne rodzaje tego, co starsi nazywaliby RAID-em o podwójnej (przekątnej) parzystości. 1, 2 i 3 odnoszą się do liczby bloków parzystości przydzielonych dla każdej grupy danych. Zamiast oddzielnych dysków do zapewnienia parzystości, wirtualne urządzenia RAIDz rozkładają tę parzystość półjednostajnie na dyskach. Zestaw RAIDz może stracić tyle dysków, ile ma bloków parzystości; jeśli straci jeszcze jeden, ulegnie awarii i zabierze ze sobą pulę pamięci.
W lustrzanych wirtualnych urządzeniach (mirror vdev) każdy blok jest przechowywany na każdym urządzeniu w vdev. Chociaż najczęściej występują podwójne lustra (two-wide), w lustrze może być dowolna liczba urządzeń — w dużych instalacjach, aby zwiększyć wydajność odczytu i odporność na awarie, często stosuje się potrójne. Lustro vdev może przetrwać każdą awarię, o ile przynajmniej jedno urządzenie w vdev działa.
Pojedyncze vdev z definicji są niebezpieczne. Takie wirtualne urządzenie nie przetrwa żadnej awarii — i jeśli jest używane jako magazyn lub specjalne vdev, jego awaria spowoduje zniszczenie całej puli. Bądź tutaj bardzo, bardzo ostrożny.
Wirtualne urządzenia CACHE, LOG i SPECIAL mogą być tworzone w dowolnej z powyższych topologii — ale pamiętaj, że utrata wirtualnego urządzenia SPECIAL oznacza utratę puli, dlatego zdecydowanie zaleca się zastosowanie topologii nadmiarowej.
urządzenie
Prawdopodobnie to najłatwiejszy do zrozumienia termin w ZFS — to dosłownie blokowe urządzenie dostępu losowego. Pamiętaj, że wirtualne urządzenia składają się z oddzielnych urządzeń, a pula jest zbudowana z wirtualnych urządzeń.
Dyski — magnetyczne lub półprzewodnikowe — są najczęściej używanymi blokowymi urządzeniami, które służą jako budulce vdev. Jednak każdy urządzenie z deskryptorem w /dev nadaje się — więc jako oddzielne urządzenia można użyć całych sprzętowych zestawów RAID.
Prosty plik raw jest jednym z najważniejszych alternatywnych blokowych urządzeń, z których może być zbudowane vdev. Testowe pule z to bardzo wygodny sposób na testowanie poleceń puli oraz sprawdzanie, ile miejsca jest dostępne w puli lub w wirtualnym urządzeniu danej topologii.

Możesz utworzyć testowy pul z rozproszonych plików w zaledwie kilka sekund — ale nie zapomnij potem usunąć całego pulu i jego komponentów.
Załóżmy, że chcesz zainstalować serwer z ośmioma dyskami i planujesz użyć dysków o pojemności 10 TB (~9300 GiB) — ale nie jesteś pewien, która topologia najlepiej odpowiada Twoim potrzebom. W powyższym przykładzie budujemy testowy pul z rozproszonych plików w kilka sekund — i teraz wiemy, że RAIDz2 vdev z ośmioma dyskami po 10 TB zapewnia 50 TiB użytecznej pojemności.
Kolejną szczególną klasą urządzeń są SPARE (rezerwowe). Urządzenia hot-swappable, w przeciwieństwie do zwykłych urządzeń, należą do całego pulu, a nie do jednego wirtualnego urządzenia. Jeśli jakieś vdev w pulu zawodzi, a rezerwowe urządzenie jest podłączone i dostępne, automatycznie dołączy do uszkodzonego vdev.
Po podłączeniu do uszkodzonego vdev rezerwowe urządzenie zaczyna otrzymywać kopie lub rekonstrukcje danych, które powinny być na brakującym urządzeniu. W tradycyjnym RAID nazywa się to odbudową (rebuilding), a w ZFS to «odtwarzanie nadmiaru» (resilvering).
Ważne jest, aby pamiętać, że rezerwowe urządzenia nie zastępują na stałe uszkodzonych urządzeń. To tylko tymczasowe zastępstwo w celu skrócenia czasu, w którym vdev jest w stanie degradacji. Po tym, jak administrator wymieni uszkodzone urządzenie vdev, następuje odbudowa nadmiaru na to stałe urządzenie, a SPARE odłącza się od vdev i wraca do pracy jako rezerwowe dla całego pulu.
Zbiory danych, bloki i sektory
Następnym zestawem elementów, które należy zrozumieć w naszej podróży po ZFS, nie są tak bardzo sprzętem, jak tym, jak dane są zorganizowane i przechowywane. Pomijamy tu kilka poziomów — takich jak metaslab — aby nie przytłaczać szczegółami, zachowując zrozumienie ogólnej struktury.
Zbiór danych (dataset)

Gdy po raz pierwszy tworzymy zbiór danych, pokazuje on całkowitą dostępną przestrzeń pulu. Następnie ustalamy kwotę — i zmieniamy punkt montowania. Magia!

Zvol to w zasadzie po prostu zbiór danych pozbawiony swojego poziomu systemu plików, który zastępujemy tutaj całkowicie normalnym systemem plików ext4.
Zestaw danych ZFS jest w przybliżeniu analogiczny do standardowego zamontowanego systemu plików. Tak jak typowy system plików, na pierwszy rzut oka wydaje się być „po prostu kolejnym folderem”. Jednak podobnie jak w przypadku typowych zamontowanych systemów plików, każdy zestaw danych ZFS ma własny zestaw podstawowych właściwości.
Przede wszystkim, zestaw danych może mieć przydzieloną kwotę. Jeśli ustawisz zfs set quota=100G poolname/datasetname, to nie będziesz mógł zapisywać w zamontowanym folderze /poolname/datasetname więcej niż 100 GiB.
Zauważyłeś obecność — i brak — ukośników na początku każdej linii? Każdy zestaw danych ma swoje miejsce zarówno w hierarchii ZFS, jak i w hierarchii montowania systemu. W hierarchii ZFS nie ma wiodącego ukośnika — zaczynasz od nazwy puli, a następnie przechodzisz od jednego zestawu danych do następnego. Na przykład, pool/parent/child dla zestawu danych o nazwie child pod rodzicem zestawu danych parent w puli o kreatywnej nazwie pool.
Domyślnie, punkt montowania zestawu danych będzie równy jego nazwie w hierarchii ZFS, z ukośnikiem na początku — pula o nazwie pool zamontowana jako /pool, zestaw danych parent zamontowany w /pool/parent, a zestaw danych podrzędny child zamontowany w /pool/parent/child. Jednak punkt montowania zestawu danych w systemie można zmienić.
Jeśli określimy zfs set mountpoint=/lol pool/parent/child, to zestaw danych pool/parent/child będzie zamontowany w systemie jako /lol.
Oprócz zestawów danych, musimy wspomnieć o woluminach (zvols). Wolumin jest w przybliżeniu podobny do zestawu danych, z wyjątkiem tego, że nie ma w nim faktycznie systemu plików — to po prostu urządzenie blokowe. Możesz, na przykład, utworzyć zvol z nazwą mypool/myzvol, a następnie sformatować je z systemem plików ext4, a następnie zamontować ten system plików — teraz masz system plików ext4, ale z obsługą wszystkich funkcji zabezpieczeń ZFS! Może się to wydawać głupie na jednym komputerze, ale ma znacznie więcej sensu jako backend przy eksportowaniu urządzenia iSCSI.
Bloki

Plik jest reprezentowany przez jeden lub kilka bloków. Każdy blok jest przechowywany na jednym wirtualnym urządzeniu. Rozmiar bloku jest zazwyczaj równy parametrowi recordsize, ale może być zmniejszony do 2^ashift, jeśli zawiera metadane lub mały plik.

Rzeczywiście, naprawdę nie żartujemy o ogromnym spadku wydajności, jeśli ustawisz zbyt mały ashift.
W puli ZFS wszystkie dane, w tym metadane, są przechowywane w blokach. Maksymalny rozmiar bloku dla każdego zbioru danych jest określany w właściwości recordsize (rozmiar rekordu). Rozmiar rekordu może się zmieniać, ale nie wpłynie to na rozmiar lub lokalizację jakichkolwiek bloków, które już zostały zapisane w zbiorze danych — działa to tylko dla nowych bloków w miarę ich zapisywania.
Jeśli nie określono inaczej, bieżący rozmiar rekordu domyślnie wynosi 128 KiB. Jest to swoisty, niełatwy kompromis, w którym wydajność nie będzie idealna, ale również nie będzie straszna w większości przypadków. Recordsize można ustawić na dowolną wartość od 4K do 1M (z dodatkowymi ustawieniami recordsize można ustawić jeszcze więcej, ale rzadko jest to dobrym pomysłem).
Każdy blok odnosi się do danych tylko jednego pliku — nie można wcisnąć dwóch różnych plików w jeden blok. Każdy plik składa się z jednego lub kilku bloków, w zależności od rozmiaru. Jeśli rozmiar pliku jest mniejszy niż rozmiar rekordu, zostanie zapisany w bloku mniejszego rozmiaru — na przykład blok z plikiem 2 KiB zajmie tylko jeden sektor 4 KiB na dysku.
Jeśli plik jest wystarczająco duży i wymaga kilku bloków, wszystkie zapisy tego pliku będą miały rozmiar recordsize — w tym ostatni zapis, którego główna część może okazać się .
W woluminach zvol nie ma właściwości recordsize — zamiast tego mają ekwiwalentną właściwość volblocksize.
Sektory
Ostatnim, najbardziej podstawowym budulcem są sektory. To najmniejsza fizyczna jednostka, która może być zapisana lub odczytana z podstawowego urządzenia. Przez kilka dziesięcioleci w większości dysków stosowano sektory o rozmiarze 512 bajtów. W ostatnich czasach większość dysków została skonfigurowana na sektory 4 KiB, a w niektórych — szczególnie SSD — sektory 8 KiB lub nawet większe.
W systemie ZFS istnieje właściwość, która pozwala ręcznie ustawić rozmiar sektora. Ta właściwość ashift. Nieco zagmatwane jest to, że ashift jest potęgą liczby dwa. Na przykład, ashift=9 oznacza rozmiar sektora 2^9, czyli 512 bajtów.
ZFS prosi system operacyjny o szczegółowe informacje o każdym urządzeniu blokowym, gdy jest ono dodawane do nowego vdev, i teoretycznie automatycznie ustawia ashift w zależności od tych informacji. Niestety, wiele dysków kłamie na temat rozmiaru swojego sektora, aby zachować zgodność z Windows XP (który nie potrafił obsługiwać dysków o innych rozmiarach sektorów).
Oznacza to, że administrator ZFS musi znać rzeczywisty rozmiar sektora swoich urządzeń i ręcznie ustawiać ashift. Jeśli ustawiony zostanie zbyt mały ashift, to astronomicznie wzrasta liczba operacji odczytu/zapisu. Tak więc zapis 512-bajtowych 'sektorów' w rzeczywisty sektor 4 KiB oznacza konieczność zapisania pierwszego 'sektora', następnie odczytania sektora 4 KiB, zmodyfikowania go drugim 512-bajtowym 'sektorem', zapisania go z powrotem do nowego sektora 4 KiB i tak dalej dla każdego zapisu.
W rzeczywistym świecie taka kara dotyka dysków SSD Samsung EVO, dla których powinien obowiązywać ashift=13, ale te SSD kłamią na temat rozmiaru swojego sektora, dlatego domyślnie ustawia się ashift=9. Jeśli doświadczony administrator systemu nie zmieni tego parametru, to ten SSD działa wolniej od zwykłego HDD.
Dla porównania, za zbyt duży rozmiar ashift nie ma praktycznie żadnej kary. Nie ma rzeczywistego spadku wydajności, a zwiększenie nieużywanej przestrzeni jest nieskończenie małe (lub równe zeru w przypadku włączonego kompresji). Dlatego zdecydowanie zalecamy nawet tym dyskom, które naprawdę używają 512-bajtowych sektorów, aby ustawić ashift=12 lub nawet ashift=13, aby pewnie patrzeć w przyszłość.
Właściwość ashift jest ustawiane dla każdego wirtualnego urządzenia vdev, a nie dla puli, jak wielu błędnie sądzi - i nie zmienia się po ustawieniu. Jeśli przypadkowo zepsujesz ashift przy dodawaniu nowego vdev do puli, to bezpowrotnie zanieczyściłeś tę pulę urządzeniem o niskiej wydajności i najczęściej nie ma innego wyjścia, jak tylko zniszczyć pulę i zacząć od nowa. Nawet usunięcie vdev nie uratuje cię przed błędną konfiguracją. ashift!
Mechanizm kopiowania przy zapisie

Jeśli zwykły system plików musi ponownie zapisać dane - zmienia każdy blok tam, gdzie się znajduje.

System plików z kopiowaniem przy zapisie zapisuje nową wersję bloku, a następnie odblokowuje starą wersję

W abstrakcyjnym ujęciu, ignorując rzeczywiste fizyczne rozmieszczenie bloków, nasza „kometa danych” upraszcza się do „robaka danych”, który porusza się od lewej do prawej po mapie dostępnej przestrzeni

Teraz możemy dobrze zrozumieć, jak działają migawki kopiowania przy zapisie — każdy blok może należeć do kilku migawek i będzie przechowywany, dopóki wszystkie związane migawki nie zostaną usunięte
Mechanizm kopiowania przy zapisie (Copy on Write, CoW) jest fundamentalną podstawą tego, co sprawia, że ZFS jest tak niesamowitym systemem. Podstawowa koncepcja jest prosta — gdy poprosisz tradycyjny system plików o zmianę pliku, zrobi dokładnie to, co powiedziałeś. Gdy poprosisz system plików z kopiowaniem przy zapisie o to samo, powie 'dobrze' — ale skłamie.
Zamiast tego system plików z kopiowaniem przy zapisie zapisuje nową wersję zmienionego bloku, a następnie aktualizuje metadane pliku, aby zerwać powiązanie ze starym blokiem i powiązać go z nowym blokiem, który właśnie zapisałeś.
Odłączenie starego bloku i powiązanie nowego odbywa się w jednej operacji, więc nie można jej przerwać — jeśli wyłączysz zasilanie po jej wykonaniu, masz nową wersję pliku, a jeśli wyłączysz zasilanie wcześniej, masz starą wersję. W każdym przypadku w systemie plików nie wystąpią konflikty.
Kopiowanie przy zapisie w ZFS odbywa się nie tylko na poziomie systemu plików, ale także na poziomie zarządzania dyskami. Oznacza to, że ZFS nie jest podatne na dziurę w zapisie () — zjawisko, w którym pasmo zdążyło tylko częściowo zapisać przed awarią systemu, z uszkodzeniem macierzy po ponownym uruchomieniu. Tutaj pasmo jest zapisywane atomowo, vdev jest zawsze spójny, a .
ZIL: dziennik zamiarów ZFS

System ZFS obsługuje synchronizacyjne zapisy w szczególny sposób — tymczasowo, ale natychmiastowo zapisuje je w ZIL, zanim później zapisze je na stałe wraz z asynchronicznymi zapisami

Zazwyczaj dane zapisane w ZIL nigdy więcej nie są odczytywane. Ale jest to możliwe po awarii systemu

SLOG, czyli wtórne urządzenie LOG, to po prostu specjalny — i pożądany, bardzo szybki — vdev, w którym ZIL może być przechowywane oddzielnie od głównego magazynu.

Po awarii wszystkie brudne dane w ZIL są przywracane — w tym przypadku ZIL znajduje się na SLOG, więc są przywracane właśnie stąd.
Istnieją dwie główne kategorie operacji zapisu — synchroniczne (sync) i asynchroniczne (async). Dla większości obciążeń roboczych przytłaczająca większość operacji zapisu jest asynchroniczna — system plików pozwala na agregację i wydawanie ich w pakietach, co zmniejsza fragmentację i znacznie zwiększa przepustowość.
Zapisy synchroniczne to zupełnie inna sprawa. Kiedy aplikacja żąda zapisu synchronicznego, mówi systemowi plików: „Musisz to zapisać w pamięci nieulotnej, tej chwili, a przez to nie mogę zrobić nic więcej”. Dlatego zapisy synchroniczne muszą być natychmiast potwierdzane na dysku — i jeśli to zwiększa fragmentację lub zmniejsza przepustowość, tak po prostu musi być.
ZFS obsługuje zapisy synchroniczne inaczej niż zwykłe systemy plików — zamiast natychmiast wprowadzać je do zwykłego magazynu, ZFS zapisuje je w specjalnym obszarze pamięci zwanym dziennikiem zamiarów ZFS — ZFS Intent Log, czyli ZIL. Sztuczka polega na tym, że te zapisane także pozostają w pamięci, będąc agregowanymi razem z normalnymi asynchronicznymi zapytaniami o zapis, aby później zostały zrzucane do magazynu jako całkowicie normalne TXG (grupy transakcji, Transaction Groups).
W normalnym trybie pracy ZIL jest zapisywane i nigdy więcej nie odczytywane. Kiedy po kilku chwilach zapisy z ZIL są zapisywane w głównym magazynie w zwykłych TXG z pamięci operacyjnej, są odłączane od ZIL. Jedynym momentem, kiedy coś jest odczytywane z ZIL, jest przy imporcie puli.
Jeśli wystąpi awaria ZFS — awaria systemu operacyjnego lub przerwa w zasilaniu — gdy w ZIL znajdują się dane, te dane zostaną odczytane podczas następnego importu puli (na przykład, przy ponownym uruchamianiu awaryjnego systemu). Wszystko, co znajduje się w ZIL, zostanie odczytane, scalone w grupy TXG, zapisane w głównym magazynie, a następnie odłączone od ZIL w procesie importu.
Jedna z pomocniczych klas vdev nazywa się LOG lub SLOG, wtórne urządzenie LOG. Jej zadaniem jest zapewnienie puli oddzielnym, a co ważniejsze, znacznie szybszym, o bardzo wysokiej odporności na zapisy, urządzeniem vdev do przechowywania ZIL, zamiast przechowywać ZIL na głównym magazynie vdev. Sam ZIL działa tak samo niezależnie od miejsca przechowywania, lecz jeżeli vdev z LOG ma bardzo wysoką wydajność zapisu, synchrone zapisy będą następować szybciej.
Dodanie vdev z LOG do puli nie może nie potrafi poprawić wydajności asynchronicznego zapisu – nawet jeśli wymuszasz wszystkie zapisy w ZIL za pomocą zfs set sync=always, nadal będą one związane z głównym magazynem w TXG w ten sam sposób i w tym samym tempie, co bez dziennika. Jedynym bezpośrednim poprawieniem wydajności jest opóźnienie zapisu synchronizacyjnego (ponieważ większa szybkość dziennika przyspiesza realizację operacji. sync).
Jednak w środowisku, które już wymaga dużej liczby zapisów synchronizacyjnych, vdev LOG może pośrednio przyspieszyć asynchroniczny zapis i niebuforowane odczyty. Przeniesienie zapisów ZIL do oddzielnego vdev LOG oznacza mniejszą konkurencję o IOPS w głównym magazynie, co w pewnym stopniu zwiększa wydajność wszystkich operacji odczytu i zapisu.
Zrzuty
Mechanizm kopiowania przy zapisie także jest niezbędną podstawą dla atomowych momeńtąalnych zrzutów ZFS i inkrementalnej asynchronicznej replikacji. W aktywnej systemie plików istnieje drzewo wskaźników, które zaznacza wszystkie zapisy z bieżącymi danymi – gdy tworzysz zrzut, po prostu tworzysz kopię tego drzewa wskaźników.
Kiedy w aktywnej systemie plików zapisywana jest nowa wersja, ZFS najpierw zapisuje nową wersję bloku w nieużywanej przestrzeni. Następnie odłącza starą wersję bloku od obecnej systemu plików. Ale jeżeli jakiś zrzut odnosi się do starego bloku, wciąż pozostaje on niezmienny. Stary blok faktycznie nie będzie uznawany za wolną przestrzeń, dopóki wszystkie zrzuty odnoszące się do tego bloku nie zostaną zniszczone!
Replikacja

Moja biblioteka Steam w 2015 roku zajmowała 158 GiB i zawierała 126 927 plików. To dość blisko optymalnej sytuacji dla rsync – replikacja ZFS przez sieć była „tylko” 750% szybsza.

W tej samej sieci replikacja jednego 40-gigabajtowego pliku obrazu maszyny wirtualnej Windows 7 to zupełnie inna historia. Replikacja ZFS odbywa się 289 razy szybciej niż rsync — lub „zaledwie” 161 razy szybciej, jeśli masz wystarczającą wiedzę, aby wywołać rsync z opcją —inplace.

Kiedy obraz maszyny wirtualnej jest skalowany, problemy rsync również się skalują. Rozmiar 1,9 TiB nie jest duży jak na nowoczesny obraz maszyny wirtualnej — ale jest wystarczająco duży, aby replikacja ZFS była 1148 razy szybsza niż rsync, nawet z argumentem rsync —inplace.
Gdy już zrozumiesz, jak działają migawki, łatwo będzie uchwycić istotę replikacji. Ponieważ migawka to po prostu drzewo wskaźników do rekordów, oznacza to, że jeśli robimy zfs send migawkę, to wysyłamy zarówno to drzewo, jak i wszystkie związane z nim rekordy. Kiedy przesyłamy to zfs send do zfs receive do docelowego obiektu, zapisuje on zarówno rzeczywistą zawartość bloku, jak i drzewo wskaźników odwołujących się do bloków w docelowym zbiorze danych.
Wszystko staje się jeszcze ciekawsze na drugim zfs send. Teraz mamy dwa systemy, z których każdy zawiera poolname/datasetname@1, a ty robisz nową migawkę poolname/datasetname@2. Dlatego w pierwotnym pulu masz datasetname@1 i datasetname@2, a w docelowym pulu na razie tylko pierwszą migawkę. datasetname@1.
Ponieważ między źródłem a celem mamy wspólną migawkę datasetname@1, możemy zrobić inkrementalną zfs send na jej podstawie. Kiedy mówimy systemowi zfs send -i poolname/datasetname@1 poolname/datasetname@2, porównuje ono dwa drzewa wskaźników. Jakiekolwiek wskaźniki, które istnieją tylko w @2, oczywiście, odnoszą się do nowych bloków — dlatego potrzebujemy zawartości tych bloków.
W zdalnym systemie przetwarzanie inkrementalne send jest równie proste. Najpierw zapisujemy wszystkie nowe rekordy zawarte w strumieniu send, a następnie dodajemy wskaźniki do tych bloków. Voilà, mamy to @2 w nowym systemie!
Asynchroniczna replikacja inkrementalna ZFS to ogromne ulepszenie w porównaniu do wcześniejszych metod, które nie opierały się na migawkach, takich jak rsync. W obu przypadkach przekazywane są tylko zmienione dane — ale rsync musi najpierw przeczytać przeczytać wszystkie dane z obu stron, aby sprawdzić sumę i porównać ją. W przeciwieństwie do tego, replikacja ZFS nie odczytuje nic poza drzewami wskaźników — oraz jakichkolwiek bloków, które nie są reprezentowane w wspólnej migawce.
Wbudowane kompresje
Mechanizm kopiowania podczas zapisu również uprościł system wbudowanej kompresji. W tradycyjnych systemach plików kompresja jest problematyczna — zarówno stara wersja, jak i nowa wersja zmienionych danych znajdują się w tej samej przestrzeni.
Jeśli rozważymy fragment danych w środku pliku, który zaczyna swoje życie jako megabajt zer od 0x00000000 i tak dalej — łatwo go skompresować do jednego sektora na dysku. Ale co się stanie, jeśli zamienimy ten megabajt zer na megabajt nieskompresowanych danych, takich jak JPEG lub pseudolosowy szum? Niespodziewanie ten megabajt danych będzie potrzebował nie jednego, a 256 sektorów po 4 KiB, a w tym miejscu na dysku zarezerwowany jest tylko jeden sektor.
ZFS nie ma tego problemu, ponieważ zmienione wpisy są zawsze zapisywane w nieużywanej przestrzeni — oryginalny blok zajmuje tylko jeden sektor 4 KiB, a nowy wpis zajmie 256, ale to nie jest problem — niedawno zmieniony fragment z "środka" pliku byłby zapisany w nieużywanej przestrzeni, niezależnie od tego, czy zmienił swoją wielkość, więc dla ZFS to całkowicie normalna sytuacja.
Wbudowana kompresja ZFS jest domyślnie wyłączona, a system oferuje programowalne algorytmy — obecnie wśród nich są LZ4, gzip (1-9), LZJB i ZLE.
- LZ4 — to algorytm strumieniowy, który oferuje niezwykle szybkie kompresje i dekompresje oraz poprawę wydajności w większości przypadków użycia — nawet na dość wolnych CPU.
- GZIP — szanowany algorytm, który znają i kochają wszyscy użytkownicy systemów Unix. Może być realizowany z poziomami kompresji od 1 do 9, z rosnącym poziomem kompresji i użycia CPU w miarę zbliżania się do poziomu 9. Algorytm jest dobrze dopasowany do wszystkich tekstowych (lub innych bardzo kompresowalnych) zastosowań, ale w przeciwnym razie często wywołuje problemy z CPU — używaj go ostrożnie, szczególnie na wyższych poziomach.
- LZJB — oryginalny algorytm w ZFS. Jest przestarzały i nie powinien być już używany, LZ4 przewyższa go we wszystkich wskaźnikach.
- ZLE — kodowanie zerowego poziomu, Zero Level Encoding. Nie ingeruje w normalne dane, ale kompresuje długie sekwencje zer. Przydatne dla całkowicie niekompresowalnych zbiorów danych (np. JPEG, MP4 lub innych już skompresowanych formatów), ponieważ ignoruje dane niekompresowalne, a kompresuje niewykorzystaną przestrzeń w finalnych zapisach.
Zalecamy kompresję LZ4 praktycznie we wszystkich zastosowaniach; kara za wydajność w przypadku napotkania danych niekompresowalnych jest bardzo niewielka, a wzrost wydajność dla typowych danych znacząca. Kopiowanie obrazu wirtualnej maszyny dla nowej instalacji systemu operacyjnego Windows (świeżo zainstalowany system operacyjny, nie ma jeszcze żadnych danych wewnętrznych) z compression=lz4 przebiegało 27% szybciej niż z compression=none, w .
ARC — adaptacyjne zastępowanie pamięci podręcznej
ZFS to jedyny znany nam nowoczesny system plików, który wykorzystuje własny mechanizm buforowania odczytu, a nie polega na buforze stron systemu operacyjnego w celu przechowywania kopii ostatnio odczytanych bloków w pamięci RAM.
Chociaż własny bufor nie jest pozbawiony problemów — ZFS nie może reagować na nowe zapytania o przydział pamięci tak szybko, jak jądro, dlatego nowe wywołanie malloc() przydziału pamięci może zakończyć się niepowodzeniem, jeśli potrzebuje pamięci RAM, która jest obecnie zajęta przez ARC. Ale są ważne powody, by korzystać z własnego buforu, przynajmniej teraz.
Wszystkie znane nowoczesne systemy operacyjne, w tym macOS, Windows, Linux i BSD, do realizacji buforów stron wykorzystują algorytm LRU (Least Recently Used). To prymitywny algorytm, który 'podnosi' buforowany blok 'w górę kolejki' po każdym odczycie i wypiera bloki 'w dół kolejki' w miarę potrzeby, aby dodać nowe missy buforów (bloki, które miały być odczytane z dysku, a nie z buforu) w górę.
Zazwyczaj algorytm działa dobrze, ale w systemach z dużymi zestawami roboczymi LRU łatwo prowadzi do thrashingu — wypierania często potrzebnych bloków, aby zwolnić miejsce dla bloków, które nigdy nie będą więcej odczytywane z buforu.
— znacznie mniej naiwna metoda, która może być postrzegana jako "ważony" cache. Po każdym odczycie z cache'u dany blok staje się nieco "cięższy" i trudniej go usunąć — a nawet po usunięciu blok jest śledzony przez określony czas. Blok, który został usunięty, ale potem musi zostać odczytany z powrotem do cache'u, również stanie się "cięższy".
Ostatecznym rezultatem tego wszystkiego jest cache z znacznie wyższym współczynnikiem trafień (hit ratio) — stosunek trafień do cache'u (odczyty wykonywane z cache'u) do nietrafień (odczyty z dysku). To niezwykle ważna statystyka — nie tylko, że same trafienia z cache'u są obsługiwane znacznie szybciej, nietrafienia z cache'u mogą być również obsługiwane szybciej, ponieważ im więcej trafień z cache'u — tym mniej równoległych zapytań do dysku i mniejsze opóźnienie dla tych pozostałych nietrafień, które muszą być obsługiwane z dysku.
Podsumowanie
Po zapoznaniu się z podstawową semantyką ZFS — jak działa kopiowanie przy zapisie, a także relacje między pulami pamięci, wirtualnymi urządzeniami, blokami, sektorami i plikami — jesteśmy gotowi omówić rzeczywistą wydajność z realnymi danymi.
W następnej części przyjrzymy się rzeczywistej wydajności pul z lustrzanymi vdev i RAIDz, porównując je zarówno ze sobą, jak i z tradycyjnymi topologiami RAID jądra Linux, które badaliśmy. .
Początkowo chcieliśmy skupić się tylko na podstawach — samych topologiach ZFS — ale po tak dużą będziemy gotowi mówić o bardziej zaawansowanej konfiguracji i tuningu ZFS, w tym o użyciu pomocniczych typów vdev, takich jak L2ARC, SLOG i Special Allocation.
Źródło: habr.com
