xandeadx.ru Блог музицирующего веб-девелопера

Drupal → Избавляемся от состояния гонки (race condition) при выполнении длительных операций

Опубликовано в

Стандартная ситуация — есть функция, которая при открытии страницы берёт данные из кэша или генерит их если кэш пуст:

function myfunction() {
  if ($cache = cache_get('mydata')) {
    $data = $cache->data;
  }
  else {
    $data = ...;
    cache_set('mydata', $data);
  }
  return $data;
}

Если процесс генерации данных будет достаточно длинным, то в определённый момент может возникнуть так называемое состояние гонки (race condition) — это когда множество параллельных потоков будут пытаться обновить пустой или невалидный кэш, что может положить ваш сервер.

В друпале для решения подобных проблем существует механизм блокировок, состоящий из четырёх основных функций:

Пример кода с использованием Locking API:

function myfunction() {
  if ($cache = cache_get('mydata')) {
    $data = $cache->data;
  }
  elseif (lock_acquire('mydata_generated')) {
    $data = ...;
    cache_set('mydata', $data);
    lock_release('mydata_generated');
  }
  else {
    lock_wait('mydata_generated');
    return myfunction();
  }
  return $data;
}

Пример кода, когда данные в кэше нужно хранить определённое время (например 1 час):

function myfunction() {
  if ($cache = cache_get('mydata') && (REQUEST_TIME - $cache->created < 60*60 || !lock_may_be_available('mydata_generated'))) {
    $data = $cache->data;
  }
  elseif (lock_acquire('mydata_generated')) {
    $data = ...;
    cache_set('mydata', $data);
    lock_release('mydata_generated');
  }
  else {
    lock_wait('mydata_generated');
    return myfunction();
  }
  return $data;
}

Тут интересный момент — если есть просроченный кэш и стоит блокировка, то ф-я вернёт данные из кэша без ожидания завершения блокировки. lock_wait() же будет вызываться только при отсутствии данных в кэше.

Написанное актуально для Drupal 7
Похожие записи

Комментарии RSS

А я всё сижу и жду, когда кто-нибудь реализует http://alekseykorzun.com/post/49520668105/how-to-gracefully-handle-cache... в друпале. Кратко суть: начать сбрасывать кеш чуть раньше (на ttl), а пока сбрасываешь, старый кеш продлить на ttl.

You now have a pretty solid protection that stops random flood of requests that bypass your caching layer at the same time.

kalabro, блокировка предпочтительней предложенного в той статье кривого велосипеда.

Во втором примере кода строчку
lock_wait('mydata');
надо заменить на
lock_wait('mydata_generated');

исправил, спасибо

Оставить комментарий

Содержимое этого поля является приватным и не будет отображаться публично. Если у вас есть аккаунт в Gravatar, привязанный к этому e-mail адресу, то он будет использован для отображения аватара.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступные HTML теги: <a> <i> <b> <strong> <code> <ul> <ol> <li> <blockquote> <em> <s>
  • Строки и параграфы переносятся автоматически.
  • Подсветка кода осуществляется с помощью тегов: <code>, <css>, <html>, <ini>, <javascript>, <sql>, <php>. Поддерживаемые стили выделения кода: <foo>, [foo].

Подробнее о форматировании