Кожне звернення вантажить увесь 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, або ні.
Це справжнє виправлення, і про це варто сказати, бо очевидним наступним кроком був би автозавантажувач, а він тут був би великою зміною заради задачі, яку mkdir уже розв'язав двічі.
Чому це лишається
Один glob — найпростіше, що взагалі може працювати, і за виміром воно працює: третина мілісекунди, на Raspberry Pi, на шляху, який мусить бути швидким. Замінити його окремими підключеннями означає, що кожному новому файлові потрібен десь рядок, а забутий рядок дає падіння в бою замість трохи більшого завантаження.
Бракує того, що взагалі зробило це стерпним, — записаного правила: якщо файл у lib/ стає великим, він переїжджає в підкаталог і підключається там, де потрібен. Саме цього правила трималися ті два каталоги, і до сьогодні воно ніде не було записане.
Загальне формулювання нудніше за вимір. «Усе вантажить усе» зазвичай хибна форма, і варто з'ясувати, чи це вам чогось коштує, перш ніж перебудовувати. Тут це коштує 0,33 мілісекунди й чотири мегабайти, і стежити треба за чотирма мегабайтами: вони ростуть з одночасністю, а мілісекунди ні.