Одновременный вызов Memcache

Пару дней назад я был на собеседовании для среднего/старшего PHP-разработчика (провалился). Мне задали каверзный вопрос, который все еще беспокоит меня.

Представьте, что мы используем PHP + Memcached и чрезвычайно нагруженный проект (около 100 обращений в секунду и более). Нам нужно выполнить огромный SQL-запрос, поэтому мы решили кэшировать его в Memcached. Теперь срок действия кеша истек, и нам нужно снова выполнить этот огромный запрос, чтобы его закешировать, но проблема в том, что все 100 пользователей попадают на сайт одновременно, поэтому теоретически сервер выполнит SQL-запрос 100 раз. в то же время кешировать его после, поэтому сервер упадет, я думаю.

Как мы могли решить эту проблему? Я думаю, что запрос должен выполниться один раз, а еще 99 человек должны остаться и дождаться данных, существующих в Memcached.


person James May    schedule 14.02.2015    source источник


Ответы (2)


Нам нужно выполнить огромный SQL-запрос,

Как часто (допустим, ежечасно?). Сколько времени это займет (допустим, 30 минут)

Во-первых, никто (клиент, сервер, php, пользователь) не должен запускать событие, которое вызывает выполнение запроса. Вам не нужно ничего во внешнем интерфейсе, связанного с блокировкой запросов на обслуживание страниц.

Вместо этого вы выполняете запрос в фоновом режиме, в потоке, на другой машине, в задании cron (пример: запускайте запрос каждый час, чтобы получить свежие результаты). Когда запрос завершится, вы можете писать в memcache, пока система работает.

Таким образом, никакие запросы страниц не вызывают запуск запроса (и, следовательно, блокировку), кроме того, вы можете постоянно/последовательно обрабатывать 100 запросов, которые вы выполняли ранее.

Кроме того, вы не будете выполнять 100 копий запроса в mysql. Он будет выполнять некоторые параллельно (блокируя остальные), но все остальные 90~ запросов попадут в кеш запросов sql, поэтому он не будет буквально запускать запрос 100 раз.

В любом случае, я сомневаюсь, что ты хочешь работать в этом месте.

Надеюсь, это имеет смысл!

person mr-sk    schedule 14.02.2015
comment
Не такой уж сложный запрос, я думаю, что он занимает около 10 секунд, но в некоторых случаях он может привести к сбою сервера. В любом случае, ваша идея хороша, я думаю, crontab - отличное решение. Спасибо. - person James May; 14.02.2015

Мой выбор состоял бы в том, чтобы добавить дополнительный статус кеша (например, устаревший), чтобы пометить записи кеша, срок действия которых истек и которые находятся в состоянии обновления.

Поэтому, если процесс php запрашивает кэшированные данные из memcached и обнаруживает, что его состояние «истек срок действия», он устанавливает состояние «устаревшее», извлекает свежую версию из базы данных и сохраняет ее как «действительную» в memcached.

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

Теперь, если вы хотите выжать последний бит производительности, первый процесс php не будет извлекать свежие данные сам, а вместо этого делегирует эту задачу другому экземпляру (например, с rabbitmq) и также возвращает устаревшие данные.

person Pierre    schedule 14.02.2015
comment
Это кажется разумным. Но я не понимаю, где поставить статус? Где хранить устаревший результат? Я думал, что Memcached просто удалит записи, когда срок его действия истечет. - person James May; 14.02.2015
comment
Кстати, спасибо, что указали мне на Rabbitmq, я до сих пор не знал о таких программах. Я буду копаться в руководстве, потому что сейчас у меня очень размытое представление о том, как это работает. - person James May; 14.02.2015
comment
Не используйте memcache ttl. Храните дату истечения срока действия и состояние кэша в отдельной записи кэша памяти. - person Pierre; 14.02.2015