Колко всъщност струва зареждането на цялото lib/
Ред 46 от единствения входен файл на тази услуга:
foreach (glob(__DIR__ . '/lib/*.php') as $f) { require_once $f; }
Това са 65 файла и 1,5 мегабайта, които се зареждат при всяка заявка. Изображение на брояч, статистическа страница, страница 404 — все едно. Вчера това се случи 20 734 пъти.
Значение има малкото число
Зареждането на всичко от нулата, с изключен кеш на опкодовете, отнема около 132 милисекунди. Това е числото, което би превърнало това в проблем, и не това е цената, която сървърът плаща.
Когато опкодовете вече са компилирани и стоят в споделената памет, остават списъкът на директорията и по едно извикване на stat() за всеки файл, защото проверката на времевите отпечатъци е включена: 0,33 милисекунди. При вчерашния трафик това са под седем секунди работа за целия ден.
Между двете стои трето измерване, 18,2 милисекунди, направено с кеш на опкодовете, който чете от диска вместо от паметта. Това е горна граница, а не реалната стойност — така изглежда, когато кешът го има, но е по-бавен от истинския. Посочваме го, защото това е единственото „топло“ число, което може да се измери от командния ред, а да се преструваме, че не е така, би било лесната грешка.
Значи: това не струва почти нищо и не струва почти нищо единствено благодарение на нещо друго. Изключете кеша на опкодовете и същият ред струва четиристотин пъти повече. Това е истинска зависимост и си струва да се знае, че я има, вместо да бъде открита по време на обновяване.
Какво всъщност има в тези 1,5 мегабайта
Четиридесет и седем процента от тях — 715 килобайта в 26 файла — са семейства дизайни на броячи. За изчертаването на изображение на брояч е нужно точно едно от тях. Останалите 25 се зареждат, декларират и никога не се използват.
След това: 189 килобайта данни за знамена, нужни на страницата с географията; 158 килобайта библиотека за диаграми, нужни, когато нещо чертае диаграма. Нито едното, нито другото участва в доставянето на изображение на брояч, а това е заявката, на която тази услуга отговаря най-често.
Видимата цена на това е памет, а не време. Пиковата памет на заявка нараства с около четири мегабайта и за разлика от опкодовете — които са общи за всички процеси — тази част се плаща при всяка заявка, паралелно, от всеки работен процес едновременно.
Някой вече го е забелязал
Шаблонът за glob е lib/*.php. Той не е рекурсивен, а точно под него стоят две директории: lib/live/ с 229 килобайта и lib/recht/ със 182 килобайта. Четиристотин килобайта, които преди бяха в пътя на зареждане, а вече не са.
Преместени са, защото са големи и рядко нужни: разделите на статистиката и правните текстове. Целият механизъм е в това, че са една директория по-надолу. Няма конфигурация, няма отложено зареждане, няма карта за автоматично зареждане — файлът или попада в glob, или не.
Това е истинска поправка и си струва да се каже, защото очевидната следваща стъпка би била автоматичен зареждач (autoloader), а тук той би бил голяма промяна за решаване на проблем, който mkdir вече реши два пъти.
Защо остава така
Един-единствен glob е най-простото нещо, което изобщо може да работи, и по всичко личи, че работи: една трета от милисекундата, на малък сървър, по пътя, който трябва да е бърз. Ако се замени с отделен require за всеки файл, всеки нов файл ще има нужда от ред някъде, а забравеният ред води до фатална грешка в работната среда, а не до малко повече зареждане.
Това, от което наистина има нужда, е да бъде записано онова, което изобщо го направи поносимо: ако файл в lib/ стане голям, той се премества в поддиректория и се включва с require там, където се използва. Това е правилото, което тези две директории следваха, и досега то не беше записано никъде.
Общият извод е по-скучен от измерването. „Всичко зарежда всичко“ обикновено е грешната форма и си струва да се измери колко струва, преди да се преустройва. Тук струва 0,33 милисекунди и четири мегабайта, и именно четирите мегабайта си струва да се следят, защото растат с броя на едновременните заявки, а милисекундите не.