Этот вопрос о лучших практиках в архитектуре.
Наша текущая архитектура
У меня есть класс PHP, который обращается к MySQL для получения информации о пользователе. Давайте назовем это User
. User
Доступ осуществляется много раз, поэтому мы реализовали слои кэширования для уменьшения нагрузки.
Первый уровень - это то, что мы называем кешем «на запрос». После того, как данные были получены из MySQL, мы храним данные в частной собственности User
. Любые последующие запросы данных возвращают свойство вместо повторного запроса данных из MySQL.
Поскольку веб-запрос живет и умирает для каждого отдельного запроса, этот кеш не позволяет приложению обращаться к MySQL более одного раза за один запрос.
Наш второй слой - Memcached. Когда приватное свойство пусто, мы сначала проверяем Memcached на данные. Если Memcached пуст, мы запрашиваем данные в MySQL, обновляем Memcached и обновляем приватное свойство User
.
Вопрос
Наше приложение - игра, и иногда обязательно, чтобы некоторые данные были как можно более актуальными. В течение примерно пяти минут запрос на чтение пользовательских данных может происходить 10 или 11 раз; тогда может произойти обновление. Последующие запросы на чтение должны быть обновлены, иначе игровая механика потерпит неудачу.
Итак, мы сделали фрагмент кода, который выполняется, когда происходит обновление базы данных. Этот код устанавливает ключ в Memcached с обновленными данными, поэтому все последующие запросы к Memcached являются актуальными.
Это оптимально? Есть ли какие-то проблемы с производительностью или другие "ошибки", о которых мы должны знать, пытаясь поддерживать своего рода "живой кэш", подобный этому?
источник
Ответы:
Я рекомендую взглянуть на ваш профиль использования и ваши требования к кешу.
Я не вижу причин, по которым вы бы оставили устаревшие данные в memcached. Я думаю, что вы выбрали правильный подход, то есть: обновить БД.
В любом случае вам понадобится оболочка для обновления вашей БД (что вы и сделали). Ваш код для обновления Пользователя в БД и в ОЗУ должен также выполнить push в memcached, ИЛИ истечение срока действия в memcached.
Например - если ваши пользователи обычно обновляют данные один раз за сеанс в рамках выхода из системы, нет особого смысла обновлять данные в кеше (например, общее количество баллов) - вы должны сразу же истечь.
Если, однако, они собираются обновить данные (например, текущее состояние игры), а затем через 0,2 секунды у вас будет немедленное попадание на страницу PHP, которая будет запрашивать данные, вы хотите, чтобы они были свежими в кеше.
источник
Я бы так не поступил, как вы обрисовали. Что вам нужно сделать, это решить, действительно ли вам НУЖНО полностью обновлять данные. Затем, если вам это нужно, решите, какие части данных должны постоянно обновляться, и отделите их от вещей, которые можно кэшировать в вашей архитектуре.
Например, вы, вероятно, захотите обновить адрес электронной почты вашего пользователя, как только он изменит его, поэтому вы не будете отправлять письма по неправильному адресу, но вряд ли дата рождения или фамилия пользователя будет полностью обязательной. современные, чтобы обеспечить достойный пользовательский опыт. (Примечание: я не использую пример игровой архитектуры, так как не знаю, на какую игру нацеливаться, и я думаю, что этот довольно легко понять).
Таким образом, у вас есть два четких набора данных: краткосрочные и долгосрочные кешируемые данные. Вероятно, вы можете избежать использования длительности кэша в минуту или около того для краткосрочных данных, просто чтобы уменьшить нагрузку на БД, но долгосрочные данные могут быть оставлены в кэше на длительность скольжения до тех пор, пока используемый.
Тогда вам нужно иметь дело с обновлениями. Сначала я бы посмотрел на использование триггера БД для простого удаления элементов из кэша, как только они устарели. Это заставит ваш бизнес-уровень инициировать обновление кэша при следующем запросе данных, освобождая некоторое пространство в кэше, если данные не используются (например, если пользователь меняет свой адрес электронной почты, а затем немедленно выходит из системы) , Если это вызовет проблемы с производительностью в пользовательском интерфейсе (то есть создаст слишком большую задержку при ожидании обновлений кэша), тогда вы можете просто инициировать вызов кэша после удаления элемента из кэша. Я также хотел бы взглянуть на оптимизацию времени чтения БД для этого небольшого набора данных, чтобы гарантировать, что любая задержка, вызванная обновлением кэша, минимальна (это должно быть проще, поскольку вам нужно только загружать данные, которые вам действительно нужны).
В любом случае я бы не стал добавлять дополнительный метод заполнения кэша, так как тогда вам нужно будет поддерживать вызов (и хуки API и т. Д.) В двух местах.
Что касается ошибок, главное, что вы должны быть осторожны, если вы пишете прямо в кеш, это синхронизация. Если многие потоки пытаются прочитать, пока вы выполняете автоматическое обновление, у вас могут возникнуть серьезные проблемы с недействительными данными, что в первую очередь лишит смысла попытки обновлять данные.
источник