Dog-pile effect или блокировка в Memcached
Недавно столкнулся с проблемой когда, при истечении срока записи в Memcached все запросы стремились к БД, что вызвало его падение. Эти запросы были очень сложными плюс операции с полученными данными данными.
Нашел в сети описание этой проблемы и даже название "Dog-pile effect".
Детальное описание проблемы
Клиент обращается в Memcached серверу и пытается достать данные по ключу. Не получив нужной записи он лезет в БД.
Проблема возникает тогда, когда несколько клиентов параллельно обращаются к БД, так как не нашли данных в кеше.
Так как запрос к БД сложный и одновременно выполняется для нескольких клиентов, то адекватный временной порог превышается.
В этот момент, еще несколько дополнительных клиентов пытаю достать данные из БД. И так идет по нарастающей.
Это может вызвать большую нагрузку на сервер MySQL, а может и падение.
Решение
Решение для Memcached было простым.
Во первых ставим бесконечное хранение для нужной записи.
Во вторых создается запись, при помощи метода Memcached::add(), которая имитирует блокировку.
Если в тот момент, если другой клиент попытается создать этот ключ то получить в ответ FALSE. Т.е. этот клиент не сможет перестроить кеш, а будет использовать старые данные.
Клиент получивший первый доступ к записи блокировщику и перестраивает кеш.
Так как запись имеет бесконечный срок хранения, для определения устаревших данных пришлось хранить эти данные в самой записи. При перестройки кеша меняется и срок хранения. И удаляет блокировщик.
Ну и напоследок пример реализации.
Нашел в сети описание этой проблемы и даже название "Dog-pile effect".
Детальное описание проблемы
Клиент обращается в Memcached серверу и пытается достать данные по ключу. Не получив нужной записи он лезет в БД.
Проблема возникает тогда, когда несколько клиентов параллельно обращаются к БД, так как не нашли данных в кеше.
Так как запрос к БД сложный и одновременно выполняется для нескольких клиентов, то адекватный временной порог превышается.
В этот момент, еще несколько дополнительных клиентов пытаю достать данные из БД. И так идет по нарастающей.
Это может вызвать большую нагрузку на сервер MySQL, а может и падение.
Решение
Решение для Memcached было простым.
Во первых ставим бесконечное хранение для нужной записи.
Во вторых создается запись, при помощи метода Memcached::add(), которая имитирует блокировку.
Если в тот момент, если другой клиент попытается создать этот ключ то получить в ответ FALSE. Т.е. этот клиент не сможет перестроить кеш, а будет использовать старые данные.
Клиент получивший первый доступ к записи блокировщику и перестраивает кеш.
Так как запись имеет бесконечный срок хранения, для определения устаревших данных пришлось хранить эти данные в самой записи. При перестройки кеша меняется и срок хранения. И удаляет блокировщик.
Ну и напоследок пример реализации.
<?php
$memcache = new Memcached;
$memcache->addServer('localhost', 11211);
$key = 'test';
$lock = $memcache->add('lock:' . $key, 1, false, 5);
if($lock)
{
// Так запись создалась мы можем делать перестаивать кеш
$value = $memcache->get($key);
$memcache->set($key, $value + 1);
// Удаляем блокировщик
$memcache->delete('lock:' . $key);
}
else
{
// так как другой клиент видимо уже работает над обновление кеша
// мы можем использовать старые данные
}
?>
Если будут вопросы, рад ответить.
Комментарии
Отправить комментарий