Kolik doopravdy stojí načítání celého lib/
Řádek 46 jediného vstupního souboru této služby:
foreach (glob(__DIR__ . '/lib/*.php') as $f) { require_once $f; }
To je 65 souborů a 1,5 megabajtu, načítaných při každém požadavku. Obrázek počítadla, stránka statistik, chyba 404 — všechno stejně. Včera se to stalo 20 734krát.
Rozhoduje to malé číslo
Načíst to všechno od nuly, s vypnutou mezipamětí opkódů, trvá asi 132 milisekund. To je číslo, kvůli kterému by to byl problém, a není to číslo, které server platí.
Když jsou opkódy už zkompilované a drží se ve sdílené paměti, zbývá výpis adresáře a jedno stat() na každý soubor, protože je zapnuté ověřování časových razítek: 0,33 milisekundy. Při včerejším provozu je to za celý den méně než sedm sekund práce.
Mezi tím leží třetí měření, 18,2 milisekundy, pořízené s mezipamětí opkódů, která čte z disku místo z paměti. Je to horní mez, ne skutečná hodnota — ukazuje, co se stane, když mezipaměť existuje, ale je pomalejší než ta skutečná. Uvádí se proto, že je to jediné teplé číslo, které se dá změřit z příkazové řádky, a předstírat opak by byla snadná chyba.
Takže: stojí to skoro nic, a stojí to skoro nic výhradně díky něčemu jinému. Vypněte mezipaměť opkódů a tentýž řádek stojí čtyřistakrát víc. To je skutečná závislost a stojí za to o ní vědět, místo abyste ji objevili při aktualizaci.
Co doopravdy je v těch 1,5 megabajtu
Čtyřicet sedm procent — 715 kilobajtů ve 26 souborech — tvoří rodiny designů počítadel. Vykreslení obrázku počítadla potřebuje přesně jednu z nich. Zbylých 25 se načte, deklaruje a nikdo se jich nedotkne.
Dále: 189 kilobajtů dat vlajek, potřebných na stránce se zeměpisem; 158 kilobajtů knihovny grafů, potřebných, když se něco kreslí do grafu. Ani jedno se nepodílí na doručení obrázku počítadla, což je požadavek, na který tato služba odpovídá častěji než na jakýkoli jiný.
Viditelnou cenou je paměť, ne čas. Špičková paměť na požadavek vzroste asi o čtyři megabajty a na rozdíl od opkódů — které sdílejí všechny procesy — se tahle část platí za každý požadavek, souběžně, všemi workery najednou.
Někdo si toho už všiml
Glob je lib/*.php. Není rekurzivní a těsně pod ním leží dva adresáře: lib/live/ s 229 kilobajty a lib/recht/ se 182 kilobajty. Čtyři sta kilobajtů, které dřív byly v cestě načítání a teď nejsou.
Přesunuly se, protože jsou velké a potřebné zřídka: sekce statistik a právní texty. Být o jeden adresář hlouběji je celý mechanismus. Žádná konfigurace, žádný líný zavaděč, žádná mapa autoloadu — soubor buď v globu je, nebo není.
To je skutečná oprava a stojí za to to říct, protože zjevným dalším krokem by byl autoloader, a autoloader by tu byl velkou změnou řešící problém, který jediný mkdir vyřešil už dvakrát.
Proč zůstává
Jediný glob je to nejjednodušší, co vůbec může fungovat, a podle všeho funguje: třetina milisekundy, na malém serveru, na cestě, která musí být rychlá. Nahradit ho samostatnými require pro každý soubor znamená, že každý nový soubor potřebuje někde řádek, a řádek, na který se zapomene, způsobí v produkci fatální chybu místo o trochu většího načítání.
Co ale potřebuje, je sepsat to, díky čemu vůbec přežil: když soubor v lib/ zbytní, přesune se do podadresáře a načte se přes require tam, kde se používá. Právě tímto pravidlem se ty dva adresáře řídily, a až dosud nebylo nikde zapsané.
Obecná verze je nudnější než měření. „Všechno načítá všechno“ je obvykle špatný tvar a stojí za to změřit, kolik stojí, než se to přestaví. Tady to stojí 0,33 milisekundy a čtyři megabajty, a sledovat stojí za to ty čtyři megabajty, protože rostou se souběhem, kdežto milisekundy ne.