Согласованность кэша при использовании memcached и СУБД, такой как MySQL

#caching #memcached #distributed-computing #race-condition #consistency

#кэширование #memcached #распределенные вычисления #состояние гонки #согласованность

Вопрос:

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

  1. Предположим, я выполняю a get(key) из кэша, и есть ошибка в кэше. Поскольку я получаю ошибку в кэше, я извлекаю данные из базы данных, а затем выполняю a put(key,value) в кеш.
  2. Но может возникнуть условие гонки, когда какой-либо другой пользователь может удалить данные, которые я извлек из базы данных. Это удаление может произойти до того, как я внесу a put в кеш.

Таким образом, в идеале put в кэш не должно происходить, поскольку данные больше не присутствуют в базе данных.

Если запись в кэше имеет TTL, срок действия записи в кэше может истечь. Но все же есть окно, в котором данные в кэше несовместимы с базой данных.

Я искал статьи / исследовательские работы, в которых говорится о такого рода проблемах. Но я не смог найти никаких полезных ресурсов.

Ответ №1:

В этой статье приводится интересная заметка о том, как Facebook (пытается) поддерживать согласованность кэша: http://www.25hoursaday.com/weblog/2008/08/21/HowFacebookKeepsMemcachedConsistentAcrossGeoDistributedDataCenters.aspx

Вот суть статьи.

  1. Я обновляю свое имя с «Джейсон» на «Обезьяна»
  2. Мы записываем «Monkey» в главную базу данных в Калифорнии и удаляем мое имя из memcache в Калифорнии, но не в Вирджинии
  3. Кто-то заходит в мой профиль в Вирджинии
  4. Мы находим мое имя в memcache и возвращаем «Jason»
  5. Репликация догоняет, и мы обновляем подчиненную базу данных моим именем как «Обезьяна». Мы также удаляем мое имя из Virginia memcache, потому что этот объект кэша появился в потоке репликации
  6. Кто-то еще заходит в мой профиль в Вирджинии
  7. Мы не находим мое имя в memcache, поэтому мы считываем с ведомого устройства и получаем «Monkey»

Ответ №2:

Как насчет использования переменной save в memcache в качестве сигнала блокировки?

каждая отдельная команда memcache является атомарной

после извлечения данных из БД включите блокировку

после того, как вы поместите данные в memcache, отключите блокировку

перед удалением из БД проверьте состояние блокировки

Ответ №3:

Приведенный ниже код дает некоторое представление о том, как использовать операции Memcached add gets и cas реализовать оптимистичную блокировку для обеспечения согласованности кэша с базой данных.
Отказ от ответственности: я не гарантирую, что он абсолютно корректен и обрабатывает все условия гонки. Также требования к согласованности могут различаться в разных приложениях.

 def read(k):
  loop:
    get(k)
    if cache_value == 'updating':
      handle_too_many_retries()
      sleep()
      continue
    if cache_value == None:
      add(k, 'updating')
      gets(k)
      get_from_db(k)
      if cache_value == 'updating':
        cas(k, 'value:'   version_index(db_value)   ':'   extract_value(db_value))
      return db_value
    return extract_value(cache_value)

def write(k, v):
  set_to_db(k, v)
  loop:
    gets(k)
    if cache_value != 'updated' and cache_value != None and version_index(cache_value) >= version_index(db_value):
      break
    if cas(k, v):
      break
    handle_too_many_retries()

# for deleting we can use some 'tumbstone' as a cache value
  

Ответ №4:

При чтении происходит следующее:

 if(Key is not in cache){
  fetch data from db
  put(key,value);
}else{
  return get(key)
}
  

При записи происходит следующее:

 1 delete/update data from db
2 clear cache
  

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

1. пожалуйста, объясните, как исправлены условия гонки, упомянутые в вопросе. ваш ответ, по-видимому, не решает проблему.