Zbavení FileStorage závislosti na sqlite
- Panda
- Člen | 569
Zdravím všechny,
nedávno si na nette@conf.netlab.cz
kdosi stěžoval, že je FileStorage v případě použití tagů a priorit
natvrdo závislý na rozšíření sqlite. To by sice mělo být dostupné
téměř všude, i tak ale takto tvrdá závislost nemusí být výhodná.
Proto jsem dneska udělal takový experiment – celý kód, který pracuje
s sqlite žurnálem, jsem oddělil do třídy SqliteJournal
,
která implementuje nové rozhraní ICacheJournal
. To nejen
otevřelo cestu implementaci dalších „driverů“, například
Sqlite3Journal
, ale i možnost přidat podoporu pro tagy a
priority do dalších storage driverů – například do
MemcachedStorage
.
Všechny změny jsem provedl na mém forku Nette na Githubu: jsmitka/nette. I když zdrojáky úspěšně prošly Nette testy, byl bych rád, kdyby se našli dobrovolníci ochotní mé úpravy otestovat. Předem díky.
- jakubkulhan
- Člen | 55
Trošku jsem si hrál a implementoval FileJournal
. K dostání
v repozitáři jakubkulhan/nette.
Je to hlavně inspirované bitcaskem, což je úložný engine pro (asi ne až tak známou) NoSQL databázi Riak.
V principu pracuje FileJournal
následovně: jsou dva
soubory – fj
a fj.log
, fj
obsahuje
seřazená data, aby byly možné rychlé výběry podle klíče (pro tagy),
nebo pomocí rozsahu (pro prioritu). fj.log
je append-only
transakční log, do kterého se ukládají změny oproti fj
. Když
fj.log
přesáhne jistou velikost, vytvoří se nový
fj
se změnami z fj.log
, fj.log
se
vymaže a všechno začíná odznova.
Doufám, že jsem tam nenechal žádný palčivý bug a promyslel dobře všechny možné souběhové možnosti. Veškeré připomínky a patche vítány.
- David Grudl
- Nette Core | 8227
Panda napsal(a):
Proto jsem dneska udělal takový experiment – celý kód, který pracuje s sqlite žurnálem, jsem oddělil do třídy
SqliteJournal
Dobrá práce, je to ve frameworku!
- David Grudl
- Nette Core | 8227
jakubkulhan napsal(a):
Trošku jsem si hrál a implementoval
FileJournal
. K dostání v repozitáři jakubkulhan/nette.
Tohle je zajímavé. Jen si říkám, že mít ve frameworku tři typy úložiště pro tagy je zbytečné. Asi by to chtělo udělat analýzu (rychlost, dostupnost) a podle toho jeden vybrat a ostatní dát do doplňků.
- jakubkulhan
- Člen | 55
David Grudl napsal(a):
Tohle je zajímavé. Jen si říkám, že mít ve frameworku tři typy úložiště pro tagy je zbytečné. Asi by to chtělo udělat analýzu (rychlost, dostupnost) a podle toho jeden vybrat a ostatní dát do doplňků.
Udělal jsem pár benchmarků (stroj – Intel Core2 Duo 2.33GHz, 2GiB RAM, HDD Seagate 320GB 7200RPM):
1000x write FileJournal max min total avg stddev var 0.27115107 0.00164890 8.59706783 0.00859707 0.36537707 42.50019671 1000x write SqliteJournal max min total avg stddev var 0.43490696 0.02485704 49.91854858 0.04991855 0.13166808 2.63765849 1000x write SqliteJournal (sqlite3 extenze) max min total avg stddev var 0.42714691 0.01956391 39.11326289 0.03911326 0.12882443 3.29362526 1x clean FileJournal max min total avg stddev var 0.41579294 0.41579294 0.41579294 0.41579294 0.00000000 0.00000000 1x clean SqliteJournal max min total avg stddev var 0.34027696 0.34027696 0.34027696 0.34027696 0.00000000 0.00000000 1x clean FileJournal max min total avg stddev var 0.00250816 0.00250816 0.00250816 0.00250816 0.00000000 0.00000000 1x clean SqliteJournal max min total avg stddev var 0.00097013 0.00097013 0.00097013 0.00097013 0.00000000 0.00000000 write FileJournal, konkurence: 30, kol: 5 max min total avg stddev var 3.73856902 0.00193906 51.43360853 0.34519200 1.23055655 3.56484664 write SqliteJournal, konkurence: 30, kol: 5 max min total avg stddev var 3.13552189 0.04577208 27.43233228 0.18288222 0.97480949 5.33025854 write FileJournal, konkurence: 5, kol: 30 max min total avg stddev var 0.53182602 0.00178289 3.50739574 0.02338264 0.63881205 27.31993038 write SqliteJournal, konkurence: 5, kol: 30 max min total avg stddev var 0.28351498 0.04531598 10.48244286 0.06988295 0.16275278 2.32893394
SqliteJournal
používal (není-li uvedeno jinak) extenzi
sqlite
. Konkureční benchmarky probíhají tím způsobem, že
v několika kolech se spustí naráz určitý počet zápisů a po jedné
sekundě se přejde na další kolo (na to, až zápisy doběhnout, se čeká
až na konci, ne mezi jednotlivými koly).
Z benchmarků je vidět, že FileJournal
vede co se týče
zápisů do určitého stupně konkurence. Při mazání ze žurnálu vyhrává
SqliteJournal
. Také stojí za povšimnutí, že časy u
FileJournal
u jsou dost rozptýlené – to proto, že
vytváření nového fj
souboru z logu je nákladná operace
(u SQLite probíhá něco podobného taky /nevím, jestli SQLite vytvoří
nový soubor, kterým přepíše ten starý, nebo provádí garbage collection
přímo v souboru s databází/, nicméně to probíhá méně často než u
FileJournal
u a je to rychlejší) a probíhá poměrně často
(jde o kompromis mezi tím, jestli častěji vytvářet nový fj
,
nebo načítat velký fj.log
).
Jinak FileJournal
myslím neaspiruje na to, aby se stal hlavním
žurnálem, spíše je zamýšlen jako fallback řešení, když všechna
ostatní nejsou dostupná kvůli nepřítomnosti potřebných extenzí.
- MzK
- Člen | 127
sry, že otevírám starší topic, dostal jsem se na něj googlením
„FileJournal nette“.
Jen bych chtěl upozornit, na drobnou nekompatibilitu s původním
FileStorage.
Viz příklad:
<?php
/* to substr tam je, abych zabránil velkému množství souboru v 1 složce. Článků je hodně a tak je ukládám do /clanky/1/, clanky/2/ clanky/a/, clanky/c/ … a pod dle prvního písmene hashe názvu.
*/
$storage = new FileStorage(TEMP_DIR . "/clanky/".substr(md5($page), 0,1)); //puvodní funguje, neexistující složky vytvoří
$storage = new FileJournal(TEMP_DIR . "/clanky/".substr(md5($page), 0,1)); // zde skončí chybou
//InvalidStateException
//Cannot open logfile /var/www/web.tld/www/../temp/clanky/1/fj.log for journal.
?>
A zrovna řeším co s tím a jak to spravit, aby mi to fungovalo, na hostingu nemám sqlite, proto.
- jakubkulhan
- Člen | 55
zacatecnik napsal(a):
sry, že otevírám starší topic, dostal jsem se na něj googlením „FileJournal nette“.
Jen bych chtěl upozornit, na drobnou nekompatibilitu s původním FileStorage.
Viz příklad:<?php /* to substr tam je, abych zabránil velkému množství souboru v 1 složce. Článků je hodně a tak je ukládám do /clanky/1/, clanky/2/ clanky/a/, clanky/c/ … a pod dle prvního písmene hashe názvu. */ $storage = new FileStorage(TEMP_DIR . "/clanky/".substr(md5($page), 0,1)); //puvodní funguje, neexistující složky vytvoří $storage = new FileJournal(TEMP_DIR . "/clanky/".substr(md5($page), 0,1)); // zde skončí chybou //InvalidStateException //Cannot open logfile /var/www/web.tld/www/../temp/clanky/1/fj.log for journal. ?>
A zrovna řeším co s tím a jak to spravit, aby mi to fungovalo, na hostingu nemám sqlite, proto.
Žurnál je vytvářen
přes Environment
, takže FileStorage
by měla
vytvořit adresář pro něj dříve, než je otevřen žurnál. Tady je patch
pro vytváření adresáře přímo ve FileJournal
u. Ale
obávám se, že stejné chování bude vykazovat i
SqliteJournal
.
Osobně bych se nebál vytvářet hodně souborů v jednom adresáři (kolik
chceš mít položek v keši /řádově/? miliony?) a věřil filesystému, že
to zvládne. Jinak, pokud vím, FileStorage
vytváří pro každý
namespace vlastní adresář, takže bych spíše využil namespaců
($cache = new Nette\Caching\Cache(new Nette\Caching\FileStorage(TEMP_DIR), 'clanky-' . substr(md5($page), 0, 1));
).
- jakubkulhan
- Člen | 55
hrach napsal(a):
Jakub: listování adresáře s pár tisíci soubory linux opravdu nezvládá.
To bude silně závislé na použitém filesystému. I pro blbé staré ext3 to vypadá takhle (Intel Core 2 Duo 2,66GHz, HDD 300GB 7200RPM):
$ mkdir test
$ cd test
$ time for i in `seq 100000`; do touch $i; done # vytvořím 100000 souborů
real 2m7.387s
user 0m10.236s
sys 0m28.988s
$ time ls >/dev/null
real 0m0.445s
user 0m0.350s
sys 0m0.090s
- hrach
- Člen | 1838
Pánové, ale to není server, kterej s diskem pracuje :) a nepředpokládám, že máte taky v ntb raid :) ale hádat se s vámi nebudu, šlo jen o dobře míněnou radu z praxe.
Edit: možná sem to špatně napsal, nezvládá to disk, ne linux ;-) to je možná to, proč se to tak chytlo :D
Editoval hrach (6. 9. 2010 19:05)
- Panda
- Člen | 569
Jeden firemní server – Xeon X3360 @ 2.83GHz, disky 2× WDC WD5002ABYS za LSISAS1068E SAS v RAID1, ext4, LVM2:
server test # time for i in `seq 100000`; do touch $i; done
real 2m26.588s
user 0m17.434s
sys 2m10.786s
server test # time ls >/dev/null
real 0m0.154s
user 0m0.086s
sys 0m0.058s
Editoval Panda (6. 9. 2010 19:18)
- MzK
- Člen | 127
hrach: Z praxe mohu potvrdit. Pokud do té složky současně nějaký proces zapisuje, jiný z ní čte a do toho to je na sdílené hostingu, načítání aplikace se podstatně zpomalí.
Panda: To není moc reálný test, v praxi existuje nějaká fragmentace souborů, soubory jsou různě velké a různě se jmenují.
Editoval zacatecnik (6. 9. 2010 19:24)
- jakubkulhan
- Člen | 55
hrach napsal(a):
Pánové, ale to není server, kterej s diskem pracuje :) a nepředpokládám, že máte taky v ntb raid :) ale hádat se s vámi nebudu, šlo jen o dobře míněnou radu z praxe.
Edit: možná sem to špatně napsal, nezvládá to disk, ne linux ;-) to je možná to, proč se to tak chytlo :D
Uznávám, že rozdělení do více adresářů může věci urychlit. Ale
kolik věcí to ztíží? Vím o tom, že např. Git to takhle dělá –
udělá SHA1 hash položky, jestliže neexistuje, vytvoří adresář
z prvních dvou písmen hex-řetězce hashe, a objekt uloží do souboru
pojmenovaného podle zbytku hex-řetězce. Ovšem Git prostě vybírá objekty
z databáze jen podle hashe. V keši budeš třebas chtít mazat podle tagu a
budeš kvůli tomu vytvářet 16 keší a nad každou spouštět
clean()
? Nepraktické!
zacatecnik napsal(a):
hrach: Z praxe mohu potvrdit. Pokud do té složky současně nějaký proces zapisuje, jiný z ní čte a do toho to je na sdílené hostingu, načítání aplikace se podstatně zpomalí.
Stále by mě zajímalo, o jakých číslech se bavíme. Kolik článků chceš kešovat / kolik bude položek v keši celkem?
Jinak, proč jsem vůbec psal, že je to podle mě blbost. Pokud se
nepotýkáš se škálovacími problémy, je to „premature optimization“ a
„premature optimization is the root of all evil“. Zapojovat vůbec keš je
do jistého stupně k ničemu – databáze to stihne obsloužit stejně
rychle, né-li rychleji. Pak je pásmo, kdy FileStorage
je dobré
řešení. A potom bych se rozhodně nevydal tvou cestou, ale porozhlédl se po
MemcacheStorage
, nebo podobně.
zacatecnik napsal(a):
Panda: To není moc reálný test, v praxi existuje nějaká fragmentace souborů, soubory jsou různě velké a různě se jmenují.
hrach psal o listování souborů, tohle testuje rychlost listování souborů, nic jiného. Ber v potaz, že žádný benchmark nikdy nebude reálný :-) Jediné reálné statistické údaje se dají sehnat při reálném provozu.
- David Grudl
- Nette Core | 8227
FileStorage vytváří adresář jen jako vedlejší efekt, jelikož si vytváří složky pro jednotlivé namespaces. Skutečně není to záměr a spíš bych to měl fixnout. Hrozí totiž, že chybné zadání cesty k dočasnému adresáři nebude odhaleno.