В этой статье я постараюсь описать распространенную ошибку создателей систем кэширования
Началось всё в далекие времена, когда я управлял сайтами, которые были расположены на хостинге в FreeBSD jail, который был весьма ограничен в ресурсах. Почему так? Потому, что я использовал для отображения отчетов и печатных форм расширение pdflib, которого в наборе расширений на стандартном хостинге не было. Я скомпилировал там свой apache и php, залил туда документы и сайт заработал.
Всё было хорошо, пока не возникла необходимость показать на страницах сайта top10 продаваемых в магазине товаров. SQL запрос, который создавал нужный набор данных, выполнялся около 10 секунд. Ключи, explain'ы и всякое другое шаманство не помогали. Нужно было делать кэширование данных. И я, подсмотрев как это делают другие, написал код который кэшировал данные запроса.
Что делал мой код.
1. Проверял, есть ли в кэше объект с нужными данными, и, если есть, брал его из кэша и использовал полученные данные. Если его не было, я выполнял код, который формировал необходимые данные и сохранял их в кэш.
2. После использования данных запускалась процедура «сбора мусора». Объекты с просроченным временем жизни удалялись.
Вроде как всё в порядке. Я проверил работу кэша на тестовой машине с помощью утилиты ab и получил обнадеживающие результаты. После этого я залил код в jail. И лег спокойно спать.
Однако на следующий день я получил от администрации хостинга письмо о том, что мой сайт заблокирован из-за того, что он создает слишком большую нагрузку на SQL-сервер.
Ключ к разгадке мне дали графики нагрузки на сервер. Они показывали скачкообразный рост нагрузки с периодичностью примерно равной времени жизни объектов кэша. Что же было на самом деле? Всё очень просто.
В момент когда истекало время жизни объекта кэша, при выполнении запроса объект кэша удалялся. Следующий http-запрос запускал процедуру создания объекта кэша, которая длилась какое-то время и выполняла дорогостоящий запрос к SQL-серверу. За это время происходил ещё один http-запрос. Который тоже запускал процедуру создания объекта кэша. Нагрузка на сервер возрастала в два раза, что влекло увеличение времени исполнения SQL-запросов в два раза. За возросшее время ожидания исполнения SQL-запросов происходил ещё один http-запрос. И так далее.

Как этого избежать?
1. Процесс, который обнаружил что объект кэша устарел не должен его удалять.
2. Процесс, который выполняет запрос, создающий зано��о объект кэша должен установить флаг, чтобы другие процессы не запускали процедуру обновления.
3. После получения свежих данных объект кэша должен быть подменен атомарной(быстрой) операцией и после этого снят флаг.
В качестве домашнего задания проверьте, пожалуйста, как построена ваша система кеширования.
Началось всё в далекие времена, когда я управлял сайтами, которые были расположены на хостинге в FreeBSD jail, который был весьма ограничен в ресурсах. Почему так? Потому, что я использовал для отображения отчетов и печатных форм расширение pdflib, которого в наборе расширений на стандартном хостинге не было. Я скомпилировал там свой apache и php, залил туда документы и сайт заработал.
Всё было хорошо, пока не возникла необходимость показать на страницах сайта top10 продаваемых в магазине товаров. SQL запрос, который создавал нужный набор данных, выполнялся около 10 секунд. Ключи, explain'ы и всякое другое шаманство не помогали. Нужно было делать кэширование данных. И я, подсмотрев как это делают другие, написал код который кэшировал данные запроса.
Что делал мой код.
1. Проверял, есть ли в кэше объект с нужными данными, и, если есть, брал его из кэша и использовал полученные данные. Если его не было, я выполнял код, который формировал необходимые данные и сохранял их в кэш.
2. После использования данных запускалась процедура «сбора мусора». Объекты с просроченным временем жизни удалялись.
Вроде как всё в порядке. Я проверил работу кэша на тестовой машине с помощью утилиты ab и получил обнадеживающие результаты. После этого я залил код в jail. И лег спокойно спать.
Однако на следующий день я получил от администрации хостинга письмо о том, что мой сайт заблокирован из-за того, что он создает слишком большую нагрузку на SQL-сервер.
Ключ к разгадке мне дали графики нагрузки на сервер. Они показывали скачкообразный рост нагрузки с периодичностью примерно равной времени жизни объектов кэша. Что же было на самом деле? Всё очень просто.
В момент когда истекало время жизни объекта кэша, при выполнении запроса объект кэша удалялся. Следующий http-запрос запускал процедуру создания объекта кэша, которая длилась какое-то время и выполняла дорогостоящий запрос к SQL-серверу. За это время происходил ещё один http-запрос. Который тоже запускал процедуру создания объекта кэша. Нагрузка на сервер возрастала в два раза, что влекло увеличение времени исполнения SQL-запросов в два раза. За возросшее время ожидания исполнения SQL-запросов происходил ещё один http-запрос. И так далее.

Как этого избежать?
1. Процесс, который обнаружил что объект кэша устарел не должен его удалять.
2. Процесс, который выполняет запрос, создающий зано��о объект кэша должен установить флаг, чтобы другие процессы не запускали процедуру обновления.
3. После получения свежих данных объект кэша должен быть подменен атомарной(быстрой) операцией и после этого снят флаг.
В качестве домашнего задания проверьте, пожалуйста, как построена ваша система кеширования.