Read-From, Write-Through: улучшаем кеш страниц

September 19, 2008 PHP кеширование

Предыстория

Есть кеш страниц, организованный по принципу 404-й. То есть – если страница лежит в кеше, она отдается сервером без участия PHP; если ее там нет – по обработчику 404-й ошибки вызывается MainController сайта, который генерирует страницу, кладет ее в кеш и отдает клиенту.

Кроме того, страницы экспайрятся по каким-то событиям. Неважно, каким. Важно, что экспайрятся, и время от времени их нужно повторно генерировать. Это решается удалением из кеша заэкспайренной страницы, после чего при запросе страницы снова вызывается PHP.

Проблема

Если в то время, пока страница генерируется скриптом, запросить ее еще раз, будет запущен еще один экземпляр скрипта и он тоже займется страницей. А при следующем запросе – еще один. И еще. В общем, race condition и в целом неправильная ситуация.

Задача

Устранить race condition с минимальным использованием PHP (предположим, что запуск и инициализация фреймворка на PHP – дорогостоящая операция).

Решение

Суть в том, что сервер каким-то образом должен понять, что страница уже генерируется, и новый скрипт не запускать. Но каким? Углубляться в настройки nginx, который стоит на продакшн, желания нет.

Первая попытка — при запуске PHP ставить флажок «занимаюсь этой страницей», а при следующем запуске – его проверять, и если флажок стоит, то просто подождать. Плохо. Это избавляет нас от лишнего прогона скрипта, но поток PHP все равно занят.

Вторая попытка — при запуске PHP немедленно записывать в кеш пустую страницу. Плохо. Кто-то ее увидит и расстроится. Так что пустая страница проблемы не решает.

Третья попытка (и последняя)

Экспайренные страницы не удаляются из кеша, а переименовываются – например, к ним приписывается суффикс «.old». Таким образом, при обращении к странице будет вызван PHP. А PHP, увидев, что есть старый (хоть какой-то) экземпляр этой страницы, немедленно переименует ее обратно – чтобы работал кеш – а уже после этого сгенерирует новую страницу и положит ее на место устаревшей.

Бинго! PHP запускается не чаще, чем в исходной постановке задачи, а кеш стал надежнее и эффективнее.

Buy Me a Coffee at ko-fi.com