Каждое обращение грузит весь 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 миллисекунды и четыре мегабайта, и следить надо за четырьмя мегабайтами: они растут с одновременностью, а миллисекунды нет.