Vad det faktiskt kostar att ladda hela lib/
Rad 46 i den här tjänstens enda ingångsfil:
foreach (glob(__DIR__ . '/lib/*.php') as $f) { require_once $f; }
Det är 65 filer och 1,5 megabyte, som laddas vid varje förfrågan. En räknarbild, en statistiksida, en 404 — allt likadant. I går hände det 20 734 gånger.
Siffran som spelar roll är den lilla
Att ladda allt från grunden, med opcode-cachen avstängd, tar ungefär 132 millisekunder. Det är siffran som skulle göra det här till ett problem, och det är inte den siffran som servern betalar.
Med opcodes som redan är kompilerade och ligger i delat minne återstår kataloglistningen och ett stat() per fil, eftersom tidsstämpelvalideringen är påslagen: 0,33 millisekunder. Med gårdagens trafik är det under sju sekunders arbete under hela dagen.
Mittemellan ligger en tredje mätning, 18,2 millisekunder, gjord med opcode-cachen läsande från disk i stället för från minnet. Det är en övre gräns snarare än den verkliga siffran — det är vad som händer när cachen finns men är långsammare än den riktiga. Den redovisas eftersom det är den enda varma siffran som går att mäta från kommandoraden, och att låtsas något annat vore det enkla misstaget.
Alltså: det här kostar nästan ingenting, och det kostar nästan ingenting helt och hållet tack vare något annat. Stäng av opcode-cachen, så kostar samma rad fyrahundra gånger mer. Det är ett verkligt beroende, och det är bättre att veta att det finns där än att upptäcka det under en uppgradering.
Vad som faktiskt finns i de 1,5 megabyten
Fyrtiosju procent av det — 715 kilobyte fördelade på 26 filer — är designfamiljer för räknare. Att rita en räknarbild kräver exakt en av dem. De övriga 25 laddas, deklareras och rörs aldrig.
Därefter: 189 kilobyte flaggdata, som behövs på geografisidan; 158 kilobyte diagrambibliotek, som behövs när något ritar ett diagram. Inget av dem är inblandat i att leverera en räknarbild, vilket är den förfrågan som den här tjänsten besvarar oftare än någon annan.
Den synliga kostnaden för det är minne snarare än tid. Toppminnet per förfrågan ökar med ungefär fyra megabyte, och till skillnad från opcodes — som delas mellan alla processer — betalas den delen per förfrågan, parallellt, av varje arbetsprocess samtidigt.
Någon har redan märkt det
Globben är lib/*.php. Den är inte rekursiv, och två kataloger ligger precis under den: lib/live/ med 229 kilobyte och lib/recht/ med 182 kilobyte. Fyrahundra kilobyte som tidigare låg i laddningsvägen och nu inte gör det.
De flyttades eftersom de är stora och sällan behövs: statistikavsnitten och de juridiska texterna. Att ligga en katalog djupare är hela mekanismen. Det finns ingen konfiguration, ingen lat laddning, ingen autoload-karta — en fil finns antingen i globben eller inte.
Det är en verklig lösning, och det är värt att säga det, eftersom det uppenbara nästa steget vore en autoloader, och en autoloader här vore en stor ändring för att lösa ett problem som mkdir redan har löst två gånger.
Varför den får vara kvar
En enda glob är det enklaste som över huvud taget kan fungera, och enligt mätningarna fungerar den: en tredjedels millisekund, på en liten server, på den väg som måste vara snabb. Att ersätta den med require per fil innebär att varje ny fil behöver en rad någonstans, och den rad som glöms bort ger ett fatalt fel i produktion i stället för en något större laddning.
Det den däremot behöver är det som gjorde den hållbar från början, nedskrivet: om en fil i lib/ blir stor flyttas den till en underkatalog och laddas med require där den används. Det är den regel som de två katalogerna följde, och den stod inte nedskriven någonstans förrän nu.
Den allmänna versionen är tråkigare än mätningen. ”Allt laddar allt” är oftast fel form, och det är värt att mäta vad det kostar innan man bygger om det. Här kostar det 0,33 millisekunder och fyra megabyte, och de fyra megabyten är den del som är värd att hålla ögonen på, eftersom de skalar med antalet samtidiga förfrågningar och millisekunderna inte gör det.