Кэширование и избегание Cache Stampedes — несколько одновременных вычислений

У нас есть очень дорогое вычисление, которое мы хотели бы кэшировать. Итак, мы делаем нечто подобное:

my $result = $cache->get( $key );

unless ($result) {
    $result = calculate( $key );
    $cache->set( $key, $result, '10 minutes' );
}

return $result;

Теперь, во время calculate($key), прежде чем мы сохраним результат в кэше, приходит несколько других запросов, которые также начинают выполняться calculate($ key), и производительность системы страдает, потому что многие процессы вычисляют одно и то же.

Идея: Давайте поместим в кеш флаг того, что вычисляется значение, чтобы другие запросы просто ждали завершения этого единственного вычисления, чтобы все они использовали его. Что-то вроде:

my $result = $cache->get( $key );

if ($result) {
    while ($result =~ /Wait, \d+ is running calculate../) {
        sleep 0.5;
        $result = $cache->get( $key );
    }
} else {
    $cache->set( $key, "Wait, $$ is running calculate()", '10 minutes' );
    $result = calculate( $key );
    $cache->set( $key, $result, '10 minutes' );
}


return $result;

Теперь это открывает совершенно новую банку червей. Что, если $$ умрет до того, как установит кеш. Что если, что если... Все они решаемы, но поскольку в CPANнет ничего, что бы это делало (в CPAN есть что-то для всего), я начинаю задаваться вопросом:

Есть ли лучший подход? Есть ли особая причина, например. Классы Perl Cacheи Cache::Cacheне предоставляют такого механизма? Есть ли проверенный и верный шаблон, который я мог бы использовать вместо этого?

Идеальным был бы модуль CPAN с пакетом debian, который уже находится в сжатии, или момент озарения, когда я вижу ошибку своего пути... :-)

РЕДАКТИРОВАТЬ: с тех пор я узнал, что это называется Паническое бегство кэшаи обновили заголовок вопроса.

7
задан Peter V. Mørch 1 March 2016 в 20:29
поделиться