Benchmark způsobů ukládání souborů do PostgreSQL
Před nějakou dobou prezentoval článek věnovaný různým způsobům ukládání souborů do PostgreSQL databáze, v jehož závěru jsem sliboval benchmark popisovaných variant ukládání. Sice to chvíli trvalo, ale benchmark je tu ...
Benchmark je celkem jednoduchý - je vygenerován zvolený počet souborů s velikostí náhodně zvolenou z daného intervalu. Poté následuje vlastní benchmark, spočívající v uložení všech vygenerovaných souborů do databáze, jejich postupném načtení a nakonec vymazání z DB. Přitom je měřen čas potřebný na každou z uvedených tří fází.
Testovány byly následující tři způsoby ukládání souborů:
- obyčejný BYTEA sloupec - celý soubor uložen v jednom BYTEA sloupci, který je součástí vlastní tabulky
- striped BYTEA - soubor je rozdělen na segmenty dané velikosti, a tyto segmenty jsou uloženy do samostatné tabulky
- LOB - soubor je interně uložen obdobně jako "striped BYTEA" ale jedná se o funkcionalitu zabudovadou přímo do PostgreSQL, a díky tomu podporuje např. skutečný streaming apod.
Co se týká testovaných kombinací počet / velikost souborů, byly testovány celkem čtyři následující kombinace (počítané tak aby celkem daly cca 500MB):
| jméno | počet souborů | min. velikost | max. velikost | celková velikost |
|---|---|---|---|---|
| velmi malé soubory | 10000 | 10 kB | 100 kB | 537 MB |
| malé soubory | 1600 | 128 kB | 512 kB | 500 MB |
| střední soubory | 700 | 512 kB | 1 MB | 525 MB |
| velké soubory | 70 | 5 MB | 10 MB | 525 MB |
Dva z testovaných způsobů ukládání umožňují ukládání nebo čtení dat po segmentech, konkrétně:
- LOB - při čtení je možné stream číst pomocí bufferů různých velikostií
- striped LOBu - soubory je možné při ukládání dělit na segmenty různých velikostí (a následně to pochopitelně hraje roli při čtení)
S ohledem na to jsou testováno více variant s různými velikostmi segmentů, konkrétně:
- bytea - jediná varianta (nemá parametry)
- LOB - čtení streamu pomocí bufferů 512B, 1kB, 2kB, ..., 128kB a 256kB
- striped BYTEA - ukládání do segmentů 512B, 1kB, 2kB, ..., 128kB a 256kB
Několik důležitých poznámek
Hlavní část benchmarku je napsána v PHP, což souvisí s tím že se většinu menších webových projektů realizuji právě v tomto jazyce, takže právě benchmark napsaný v PHP pro mne dává nejlepší smysl. Nastavení PHP je víceméně standardní, ovšem s tím že kvůli ukládání velkých souborů do bytea sloupců byl zvýšen memory limit na 128 MB.
Použitá verze PostgreSQL byla 8.3.6 s víceméně standardním nastavením, tj. byly provedeny základní úpravy tak aby parametry odpovídaly například množství paměti (effective_cache, buffery, apod.) a podobně. Žádné speciální ladění pro tento benchmark neprobíhalo. Autovacuum démon byl ponechán zapnutý, ale byl nastaven poněkud agresivněji (nižší delay, vyšší cost limit). V případě zájmu je možné si konfigurační soubor stáhnout.
Prezentované výsledky byly naměřeny na mém domácím PC - AMD 64 X2 4400+, 2GB paměti, standardní SATA disk, Gentoo Linux (zkompilovaný pro 32bit). Na nabušeném serveru s výkonnějším HW (SCSI nebo SAS disky, lepší procesory, apod.) pochopitelně naměříte vyšší hodnoty, ale relace mezi výkonem jednotlivých způsobů ukládání zůstanou zachovány.
Soubory byly generovány do adresáře umístěného v paměti v ramfs filesystému, a to kvůli eliminaci vlivu načítání souborů z disku na benchmark. Soubory měly náhodný obsah, generovaný pomocí /dev/urandom.
Pro všechny benchmarky byla vždy použita stejná sada souborů daného typu, ale před každým benchmarkem (způsob uložení, jiná velikost segmentu) byla databáze vždy dropnuta a znovu vytvořena, a po načtení souborů do DB byl ručně spuštěn příkaz ANALYZE.
Všechny grafy uvedené v následující fázy zachycují počet vteřin potřebný k vykonání dané operace (zápis souborů do DB, jejich načtení a nakonec i smazání).
Velmi malé soubory
Při zápisu velmi malých souborů do DB jednoznačně vede použití LOBů, následované obyčejným BYTEA sloupcem. Striped BYTEA sloupce je nejpomalejší, ale s rostoucí délkou segmentu se rychle blíží BYTEA sloupci (v podstatě od 4kB je výkon srovnatelný s BYTEA sloupcem a od 8kB již měřitelný rozdíl neexistuje), což je způsobeno také malou velikostí souborů (max. 100kB) a tedy rychle klesajícím počtem segmentů.

Při čtení z databáze poněkud překvapivě velmi výrazně ztrácí řešení s LOBy (bez ohledu na velikost bufferu), zatímco BYTEA a striped BYTEA jsou v podstatě vyrovnané (opět platí že čím delší segment tím více se tato řešení blíží, aby od 4kB byla v podstatě ekvivalentní).

Při mazání souborů z databáze není mezi řešeními výrazný rozdíl - nejpomalejší je BYTEA, ale LOB je rychlejší jen o cca 10%, a striped BYTEA dosti "skáče" okolo LOBu.

Malé soubory
I v případě zápisu malých souborů (cca 128kB až 512kB) do DB jednoznačně vede použití LOBů, následované obyčejným BYTEA sloupcem, kterému ale od 4kB výrazně šlape na paty striped do BYTEA.

Čtení z databáze je ve srovnání s velmi malými soubory daleko vyrovnanější - s výjimkou velmi malých BYTEA segmentů (512B a 1kB) jsou řešení velmi vyrovnaná - nejlépe se jeví striped BYTEA se segmenty o velikosti 4kB až 64kB, následované BYTEA sloupcem. Výkon LOB řešení poměrně znatelně osciluje.

Mazání z databáze je opět velmi vyrovnané, s tím že nejrychlejší je BYTEA sloupec, LOB je o cca 20% pomalejší a striped BYTEA kolem nich osciluje - někdy je rychlejší, někdy pomalejší (v podstatě bez ohledu na velikost segmentu).

Středně velké soubory
V případě zápisu středně velkých souborů (cca 512kB až 1MB) se opakuje situace z předchozích dvou sekcí - opět celkem jasně vede použití LOBů, následované obyčejným BYTEA sloupcem, kterému se ale od 8kB celkem výrazně blíží striped BYTEA.

I u čtení z databáze se opakuje situace z předchozího odstavce - s výjimkou velmi malých BYTEA segmentů (512B a 1kB) jsou řešení dosti vyrovnaná - celkově se nejlépe jeví striped BYTEA o velikosti 4kB až 64kB, následované BYTEA sloupcem a LOB řešeními (které tentokrát takřka vůbec neosciluje).

I mazání z databáze je opět velmi vyrovnané, s tím že nejrychlejší je BYTEA sloupec, LOB je o cca 20% pomalejší a striped BYTEA kolem nich osciluje - někdy je rychlejší, někdy pomalejší.

Velké soubory
I v případě zápisu velkých souborů (cca 5MB až 10MB) se opakuje situace z předchozích dvou sekcí - opět celkem jasně vede použití LOBů, následované obyčejným BYTEA sloupcem, kterému se ale od 8kB celkem výrazně blíží striped BYTEA.

I u čtení z databáze se opakuje situace z předchozích odstavců - s výjimkou velmi malých BYTEA segmentů (512B a 1kB) jsou řešení dosti vyrovnaná - celkově se nejlépe jeví striped BYTEA o velikosti 4kB až 64kB, následované BYTEA sloupcem a LOB řešeními.

I mazání z databáze je opět velmi vyrovnané, s tím že nejrychlejší je BYTEA sloupec, LOB je o cca 10% pomalejší a striped BYTEA kolem nich osciluje - někdy je rychlejší, někdy pomalejší.

Shrnutí
Z předchozích odstavců lze udělat několik následujících závěrů:
- Mazání je ve všech případech naprosto srovnatelné - žádné řešení nijak výrazně nevybočuje. Pokud potřebujete řešení s rychlejším mazáním, můžete použít "lazy delete" - namísto smazání pouze označit a smazat později (například v noci z cronu apod.).
- Co se týká zápisu, jednoznačně nejrychlejší je LOB, s uctivým odstupem (50% až 100%) následovaný BYTEA sloupcem. Striped BYTEA je pro segmenty nad 4kB srovnatelné s BYTEA sloupci, přičemž je výrazně méně paměťově náročné.
- Při čtení dat se nejlépe osvědčilo striped BYTEA o velikostech mezi 8kB a 32kB, následované prostým BYTEA sloupcem, a nakonec LOB.
Závěry jsou celkem jednoduché - pokud potřebujete ukládat jen relativně malé soubory (tj. takové při jejichž escapování nedojde k vyčerpání memory limitu v PHP), bude asi nejjednodušší použít obyčejný BYTEA sloupec.
V případě větších souborů je to složitější - pokud zásadní roli hraje rychlost jejich vkládání, je asi lepší využití LOBů. Naopak pokud potřebujete brát v potaz zejména čtení, udržení integrity DB (přeci jen LOBy neumožňují cizí klíče apod.), může pro vás být výhodnější striped BYTEA.
Soubory ke stažení
- skripty pro benchmark - Předem upozorňuji že tyto skripty nejsou příliš (tj. rozuměj "vůbec") připravené na spouštění mimo můj počítač - jsou v nich cesty a přihlašovací údaje natvrdo, apod. Takže pro ilustraci jsou ideální, ale pro zprovoznění se v nich budete muset "trochu" (tj. rozuměj "hodně") povrtat.
- výsledky benchmarku - Výsledky benchmarku (výpisy z PHP skriptu a také log z dstat).




