Przy stawianiu nowego media/torrentboxa postanowiłem poeksperymentować i postawić większość systemu na btrfs (oprócz storagu dla torrentów bo COW ssie do tego i backupu z wiadomych przyczyn). Po jakimś czasie zauważyłem że z jakiegoś powodu collectd przy restarcie koszmarnie zamula serwer (load avg up, system mało responsywny itd.), pogrzebałem trochę w systemie i doszedłem do wniosku że to filesystem zamontowany na /var i procesy btrfsa. Chciałem porównać to do poprzedniego systemu (tam wszystko na reiserfs) więc po kawie myślenia rozpocząłem prosty test

Warunki testu.

  • 2 procesy collectd, karmione tymi samymi danymi
  • 718 plików RRD, zbieranie danych co 10 sek
  • CacheTimeout 900 ( http://collectd.org/documentation/manpages/collectd.conf.5.shtml#plugin_rrdtool )
  • RandomTimeout 300
  • RRARows 12000
  • Czyli w skrócie “jeżeli dane w cache w RAM są starsze niż 15 minut zrzuć je na dysk”
  • 2 partycje 3GB, jedna reiserfs druga btrfs (po skończonym teście reiser miał 1,8G used a btrfs 2,5GB co samo w sobie jest ciekawe)
  • test chodził sobie 2 dni

Wyniki

W perspektywie dnia praktycznie (uśredniona) prosta linia, zoom “godzinny”:

reiserfs

btrfs

(rozdzielczość 10s)

Czyli na pierwszy rzut oka btrfs generuje 5-6x więcej ops/sek / kb/sek niż reiserfs (czy jakikolwiek nie-COW fs). Czemu ? Pliki RRD to praktycznie worst case scenario dla tego typu sustemu plików (jako ciekawostka, zrobiłem podobny test pod zfs-fuse, wypadł jeszcze gorzej)

Jak działają pliki RRD (Round Robin Database)

W (wielkim) skrócie jest to baza danych zawierająca parę tzw. DS (Data Source), każde z nich zawiera parę RRA (Round Robin Archive) jak np MIN, MAX, AVG, które to mają parę “tabel” (z braku lepszego określenia) o różnych zakresach czasowych i dokładności np. “ostatnie 24h z dokładnością 10s”, “ostatni tydzień z dokładnością 1 min” itd.

Dzięki temu plik ma stałą wielkość przy tworzeniu (tylko tabele są wypełnione NaN) która nie rośnie z czasem; najważniejsze dane (aktualne) mają maksymalną rozdzielczość podczas gdy starsze (dane “przesuwane” z bardziej do mniej dokładnej części bazy) dane mają mniejszą dokładność, ale za to przechowywane są przez znacznie dłuższy czas.

Sam zapis polega na nadpisywaniu najstarszych danych  i ew. przenoszeniu danych (po wcześniejszym uśrednieniu) do innych tabel. Czyli 100% zapisów to rewrite istniejących danych w pliku.

Rezultat

“Zwykły” filesystem:

  • Rewrite bloku dysku (lub 2ch gdy dużo danych) per DS/RRA w pliku ( + journaling)

COW:

  • Wczytaj blok (filesystemowy, zwykle 4k lub więcej)
  • Zmień jego część i zapisz blok gdzie indziej (dodatkowy seek głowicy jeżeli akurat wolne miejsce jest daleko) ( + journal)
  • Póżniejsze zwolnienie starego bloku (jeżeli akurat nie robimy/nie jest potrzebny do snapshotu) = kolejny zapis metadanych ( + journal)

A wynikiem tego jest koszmarna wydajność w tym przypadku. Oczywiście to bardzo specyficzny case, obciążenie polegające w 100% na rewrite istniejących plików nie jest tak częste, ale pokazuje to że nie ma złotego środka jeżeli chodzi… o w sumie wszystko w IT.

Każde rozwiązanie ma swoje plusy i minusy (chociaż niektóre głównie minusy ;) ) i ślepe brnięcie w “oooo btrfs/ZFS, me like cows, mooo!” bez sprawdzenia bilansu zysków/strat może okazać się pułapką :) (patrząc z drugiej strony jeżeli wydajność w danym zastosowaniu jest “wystarczająca”, krówki dostarczają bardzo przydatnej funkcji snapshotowania. No silver bullet ;] )