Tipy pro práci s velkým množstvím malých souborů

Nápad na článek vznikl spontánně z diskuse v komentářích k článku „Něco o inodech“.

Tipy pro práci s velkým množstvím malých souborů

Jde o to, že vnitřní specifikou fungování našich služeb je uchovávání obrovského množství malých souborů. V současné době máme kolem stovek terabajtů těchto dat. A narazili jsme na některé zřejmé i méně zřejmé problémy, kterými jsme úspěšně prošli.

Proto se dělím o naše zkušenosti, možná budou někomu užitečné.

První problém: „Na zařízení není dostatek místa“

Jak bylo zmíněno v výše uvedeném článku, problém spočívá v tom, že na souborovém systému jsou volné bloky, ale inody došly.

Počet použitých a volných inode můžete zkontrolovat příkazem df -ih:

Tipy pro práci s velkým množstvím malých souborů

Nebudu znovu přepisovat článek, pokud to shrnu, na disku jsou jak bloky přímo pro data, tak bloky pro meta-informace, které jsou právě inody (indexový uzel). Jejich počet je nastaven při inicializaci souborového systému (máme na mysli ext2 a jeho následovníky) a poté se nemění. Vyvážení bloků dat a inode se počítá na základě průměrných dat, v našem případě, kdy je hodně malých souborů, by se mělo vyvážení posunout ve prospěch počtu inode — těch by mělo být více.

V Linuxu už existují varianty s různým vyvážením a všechny tyto předem vypočítané konfigurace se nacházejí v souboru /etc/mke2fs.conf.
Proto při počáteční inicializaci souborového systému prostřednictvím mke2fs můžete zadat potřebný profil.

Zde je několik příkladů ze souboru:

    small = {
        blocksize = 1024
        inode_size = 128
        inode_ratio = 4096
    }

    big = {
        inode_ratio = 32768
    }

    largefile = {
        inode_ratio = 1048576
        blocksize = -1
    }

Vybrat požadovanou variantu použití lze pomocí volby „-T“ při volání mke2fs. Také můžete ručně zadat potřebné parametry, pokud neexistuje hotové řešení.

Více podrobností je uvedeno v manuálech pro mke2fs.conf a mke2fs.

Nevyzdvihnutá v výše zmíněném článku zvláštnost — můžete nastavit velikost bloku dat. Je zřejmé, že pro velké soubory dává smysl větší velikost bloku, pro malé — menší.

Je však třeba vzít v úvahu takovou zajímavou zvláštnost, jako je architektura procesoru.
Jednou jsem si povzdechl, že pro velké soubory fotografií potřebuji větší velikost bloku. Bylo to v domácích podmínkách, na domácím úložišti od WD s architekturou ARM. Bez dlouhého přemýšlení jsem nastavil velikost bloku na 8k nebo 16k namísto standardních 4k, po předchozím přeměření úspory. Všechno bylo skvělé až do okamžiku, kdy samotné úložiště selhalo, přičemž disk byl v pořádku. Když jsem disk vložil do běžného počítače s běžným procesorem Intel, dostal jsem překvapení: nepodporovaná velikost bloku. Děs a hrůza. Data existují, všechno je v pořádku, ale není možné je přečíst. Procesory i386 a podobné neumějí pracovat s velikostmi bloku, které neodpovídají velikosti stránky paměti, a ta je přesně 4k. Celá záležitost skončila použitím utilit z uživatelského prostoru, všechno bylo pomalé a smutné, ale data byla zachráněna. Kdo má zájem — hledejte podle názvu utility. fuseext2. Morálka: buď si dopředu promyslete všechny scénáře, nebo se nechte unést a používejte standardní nastavení pro domácí uživatele.

UPD. Podle poznámky uživatele berez upřesňuji, že pro i386 velikost bloku by neměla přesáhnout 4k, ale nemusí být nutně přesně 4k, tj. jsou povoleny i 1k a 2k.

Takže, jak jsme řešili problémy.

Za prvé, problém jsme narazili, když mnohatera byte disk byl zaplněn daty a nemohli jsme předělat konfiguraci souborového systému.

Za druhé, řešení bylo potřeba urgentně.

Nakonec jsme dospěli k závěru, že je třeba změnit rovnováhu a snížit počet souborů.
Abychom snížili počet souborů, rozhodli jsme se zabalit soubory do jednoho společného archivu. Vzhledem k naší specifice jsme každý měsíc balili všechny soubory za určitý časový úsek a prováděli jsme archivaci pomocí cron úlohy každou noc.

Zvolili jsme zip archiv. V komentářích k předchozímu článku byl navržen tar, ale má jednu obtíž: nemá obsah a soubory v něm jsou uspořádány v řadě (ne nadarmo se "tar" zkracuje jako "Tape Archive", dědictví páskových úložišť), tzn. pokud potřebujete přečíst soubor na konci archivu, musíte přečíst celý archiv, protože v něm nejsou offsety pro každý soubor vzhledem k začátku archivu. A proto je to dlouhá operace. U zip je to mnohem lepší: má onen obsah a offsety souborů uvnitř archivu a čas přístupu k každému souboru nezávisí na jeho umístění. A v našem případě bylo možné nastavit možnost komprese "0", protože všechny soubory byly již předem komprimovány v gzip.

Klienti stahují soubory přes nginx, a podle starého API se uvádí prosté jméno souboru, například takto:

http://www.server.com/hydra/20170416/0453/3bd24ae7-1df4-4d76-9d28-5b7fcb7fd8e5

Abychom mohli v reálném čase rozbalovat soubory, našli jsme a připojili modul nginx-unzip-module (https://github.com/youzee/nginx-unzip-module) a nastavili dva upstreamy.

Výsledkem byla taková konfigurace:

Tipy pro práci s velkým množstvím malých souborů

Dva hostitelé v nastavení vypadaly takto:

server {
  listen *:8081;

  location / {
    root      /home/filestorage;
  }
}

server {
  listen *:8082;

  location ~ ^/hydra/(d+)/(d+)/(.*)$ {
    root      /home/filestorage;
    file_in_unzip_archivefile "/home/filestorage/hydra/$1/$2.zip";
    file_in_unzip_extract "$2/$3";
    file_in_unzip;
  }
}

A konfigurace upstreamů na výše uvedeném nginx:

upstream storage {
  server server.com:8081;
  server server.com:8082;
}

Jak to funguje:

  • Klient jde na front nginx
  • Front nginx se pokouší vrátit soubor z prvního upstreamu, tzn. přímo ze souborového systému
  • Pokud soubor neexistuje — pokusí se ho vrátit ze druhého upstreamu, který se pokouší najít soubor uvnitř archivu

Druhý problém: opět "No space left on device"

To je druhý problém, se kterým jsme se setkali, když byl v adresáři příliš mnoho souborů.
Snažíme se vytvořit soubor, systém si stěžuje, že není místo. Změníme jméno souboru a znovu se ho pokoušíme vytvořit.

Podaří se.

Vypadá to přibližně takto:

Tipy pro práci s velkým množstvím malých souborů

Kontrola inodes nic nedala — je jich mnoho volných.
Kontrola místa — totéž.
Pomysleli jsme si, že může být příliš mnoho souborů v adresáři, a na to existuje limit, ale opět ne: Maximum number of files per directory: ~1.3 × 10^20

A soubor se dá vytvořit, pokud změníte jméno.
Závěr — problém je v názvu souboru.

Další hledání ukázala, že problém je v algoritmu hashování při vytváření indexu adresáře, při velkém počtu souborů dochází ke kolizím se všemi vyplývajícími následky. Podrobněji si můžete přečíst zde: https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Hash_Tree_Directories

Tuto možnost lze vypnout, ale... hledání souboru podle názvu může být nepředvídatelně dlouhé při procházení všech souborů.

 tune2fs -O "^dir_index" /dev/sdb3

Obecně může fungovat jako dočasné řešení.

Moral: mít mnoho souborů v adresáři je obvykle špatně. Takto se to dělat nemá.

Obvykle se v takových případech vytvářejí vnořené adresáře podle prvních písmen názvu souboru nebo podle jiných parametrů, například podle dat, většinou to pomáhá.
Celkové množství malých souborů je každopádně špatné, i když jsou rozděleny po adresářích — viz první problém.

Třetí problém: jak zobrazit seznam souborů, pokud jich je mnoho

V naší situaci, kdy máme mnoho souborů, se setkáváme s problémem, jak zobrazit obsah adresáře.

Standardní řešení — příkaz ls.
Dobře, podívejme se, co dostaneme na 4772098 souborech:


$ time ls /home/app/express.repository/offercache/ >/dev/null

real	0m30.203s
user	0m28.327s
sys	0m1.876s

30 sekund... to je hodně. Většina času jde na zpracování souborů v uživatelském prostoru, a ne na práci jádra.

Ale řešení existuje:


$ time find /home/app/express.repository/offercache/ >/dev/null

real	0m3.714s
user	0m1.998s
sys	0m1.717s

3 sekundy. Desetkrát rychleji.
Hurá!

UPD.

Ještě rychlejší řešení od uživatele berez — vypnutí třídění u ls


time ls -U /home/app/express.repository/offercache/ >/dev/null
real	0m2.985s
user	0m1.377s
sys	0m1.608s

Čtvrtý problém: vysoký LA při práci se soubory

Občas nastává situace, kdy je potřeba zkopírovat spoustu souborů z jednoho stroje na druhý. Přitom často výrazně vzrůstá LA, protože vše závisí na výkonu samotných disků.

Nejrozumnější volba je použít SSD. Opravdu úžasné. Otázka je jen v ceně mnohaterarabajtových SSD.

Ale pokud jsou disky obyčejné, je třeba soubory kopírovat, a to je navíc produkční systém, kde přetížení vede k nespokojeným reakcím zákazníků? Existuje minimálně dva užitečné nástroje: nice a ionice.

nice — snižuje prioritu procesu, takže plánovač dává více časových kvantům jiným, prioritnějším procesům.
V naší praxi pomáhalo nastavit nice na maximální (19 — to je minimální priorita, -20 (minus 20) — maximální).

ionice — upravuje prioritu vstupu/výstupu (I/O scheduling)

Pokud používáte RAID a potřebujete ho náhle synchronizovat (po neúspěšném restartu nebo při obnově RAID pole po výměně disku), může být v určitých situacích smysluplné snížit rychlost synchronizace, aby ostatní procesy mohly fungovat alespoň zhruba adekvátně. K tomu pomůže následující příkaz:


echo 1000 > /proc/sys/dev/raid/speed_limit_max

Problém pátý: Jak synchronizovat soubory v reálném čase

Máme stále ty obrovské množství souborů, které je třeba zálohovat na druhý server, aby nedošlo k... Soubory se neustále zapisují, takže je potřeba je co nejrychleji kopírovat, abychom měli minimální ztráty.

Standardní řešení: Rsync přes SSH.

To je dobrá varianta, pokud to nemusíme dělat každých několik sekund. A souborů je hodně. I když je nebudeme kopírovat — přesto je třeba nějak porozumět, co se změnilo, a porovnat několik milionů souborů zabere čas a zatíží disky.

To znamená, že musíme hned vědět, co je třeba kopírovat, aniž bychom při každém spuštění provedli porovnání.

Záchrana je — lsyncd. Lsyncd — Demon pro živou synchronizaci (Mirror). Pracuje také přes rsync, ale navíc monitoruje souborový systém na změny pomocí inotify a fsevents a spouští kopírování pouze pro ty soubory, které byly přidány nebo změněny.

Problém šestý: jak pochopit, kdo zatěžuje disky

To asi ví každý, ale přesto pro úplnost obrazu: pro monitorování diskového subsystému existuje příkaz iotop — podobně jako top, ale ukazuje procesy, které nejvíce zatěžují disky.

Tipy pro práci s velkým množstvím malých souborů

Mimochodem, starý dobrý top také umožňuje pochopit, zda jsou s disky problémy nebo ne. K tomu existují dva nejvhodnější parametry: Load Average a IOwait.

Tipy pro práci s velkým množstvím malých souborů

První ukazuje, kolik procesů čeká na zpracování, obvykle více než 2 — to už něco nehraje. Při aktivním kopírování na zálohové servery tolerujeme 6-8, po tom už je situace považována za nestandardní.

Druhý — jak moc je procesor vytížen diskovými operacemi. IOwait >10% — důvod k obavám, i když na našich serverech se specifickým profilem zatížení to může být stabilně 40-50%, a to je opravdu norma.

Tímto zakončím, i když jistě existuje mnoho dalších aspektů, se kterými jsme se nemuseli setkat, s potěšením budu čekat na komentáře a popisy zajímavých reálných případů.

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster