Расскажите о нескольких реализациях согласованности базы данных и кеша.

Redis

Кэш является широко используемым компонентом в системе с высоким параллелизмом в Интернете. Из-за добавления дополнительного слоя, если он используется неправильно, это может привести к обратным результатам, например, «удалить или обновить кеш?», « оперировать сначала базой данных или сначала оперировать кешем?» Старомодная тема, сегодня мы поговорим о решении согласованности двойной записи между кешем и базой данных.

Cache Aside Pattern

В начале самый классический режим чтения и записи кэша + базы данных в рамках популярной науки — это шаблон Cache Aside.

  • При чтении сначала прочитайте кеш, если кеша нет, прочитайте базу, затем выньте данные и поместите их в кеш, и заодно верните ответ.
  • При обновлении сначала обновите базу данных, а затем удалите кеш.

Зачем удалять кеш вместо обновления кеша?

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

Сначала обновите базу данных, затем удалите кеш.

1,Успешно обновить базу данных, успешно удалить кеш,нет проблем.

2,Не удалось обновить базу, программа перехватит исключение, не перейдет к следующему шагу и несоответствия данных не будет.

3.Обновление базы данных проходит успешно, но удаление кеша не удается. База данных — это новые данные, кэш — это старые данные, и возникла несогласованность. Здесь мы рассмотрим, как это решить:

  • механизм повторной попытки, если удаление кеша не удалось, ловим это исключение и отправляем удаляемый ключ в очередь сообщений,

Затем создайте потребителя для самостоятельного использования и снова попробуйте удалить ключ. (Это приведет к вторжению в бизнес-код)

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

Короче говоря, в случае сбоя кэша после удаления наш подход заключается в следующем.продолжайте повторять попытку удалить, до успеха,Добейтесь конечной согласованности!

Сначала удалите кэш, затем обновите базу данных.

1,Успешно удалить кеш, успешно обновить базу данных,нет проблем.

2,Не удалось удалить кеш, программа перехватит исключение, не перейдет к следующему шагу и несоответствия данных не будет.

3.Удаление кэша прошло успешно, но обновить базу данных не удалось, в это время база данных содержит старые данные, а кэш пуст, поэтому данные не будут противоречивыми.

Хотя несоответствия данных нет, кажется, что проблемы нет, но вышесказанное относится к случаю одного потока, а в случае параллелизма могут возникнуть следующие сценарии:

1)线程 A 需要更新数据,首先删除了 Redis 缓存  
2)线程 B 查询数据,发现缓存不存在,到数据库查询旧值,写入 Redis,返回  
3)线程 A 更新了数据库

В настоящее время Redis — это старое значение, база данных — это новое значение, или возникла несогласованность данных.

Отсроченное двойное удаление

Для решения вышеописанной ситуации имеемОтсроченное двойное удалениестратегии, не беспокойтесь об удалении ее один раз и удалении снова через некоторое время.

1)删除缓存
2)更新数据库
3)休眠 500ms(这个时间,依据读取数据的耗时而定)
4)再次删除缓存

Псевдокод выглядит следующим образом:

public void write(String key,Object data){
   redis.delKey(key);
   db.updateData(data);
   Thread.sleep(500);
   redis.delKey(key);
}

очередь памяти

Помимо метода отложенного двойного удаления, еще одним решением является очередь памяти.Его идея заключается в следующем.сериализовать, но в этом случае пропускная способность слишком мала, что влияет на производительность и увеличивает сложность системы,просто предложи идею.

При обновлении данных мы не работаем напрямую с БД и кешем, а ставим ID данных в очередь памяти, при чтении данных обнаруживаем, что данных нет в кеше, не заходим в БД и положить его в кеш, но положить данные в кеш.Id помещается в очередь памяти.

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

Тут есть момент оптимизации, на самом деле бессмысленно связывать в очередь несколько запросов на обновление кеша, поэтому можно сделать фильтрацию, если обнаруживается, что в очереди уже есть запрос на обновление кеша, то Нет необходимости отправлять еще один запрос на обновление.После завершения операции просто дождитесь завершения предыдущего запроса на операцию обновления.

После завершения операции обновления данных в очереди памяти будет выполнена следующая операция, то есть операция чтения данных, в это время будет считано последнее значение из базы данных, а затем записано в очередь кеш. Если запрос все еще находится в диапазоне времени ожидания, и он постоянно опрашивается, чтобы определить, что значение может быть получено, он вернется напрямую; если время ожидания запроса превышает определенный период времени, он будет прочитан непосредственно из базы данных. этот раз.

Суммировать

Упомянутые выше решения относительно распространены и просты, и идеального решения не существует.Последнее отложенное двойное удаление и очередь памяти предназначены для решения проблемы удаления кеша, а затем обновления базы данных в режиме параллелизма..

Обсуждаемое сегодня обновление данных Redis и базы данных невозможно для достижения транзакции, мы можем толькосоответствующая сценаа такжецена, которую нужно заплатитьЧтобы принять некоторые меры для снижения вероятности несогласованности данных, добиться компромисса между согласованностью данных и производительностью и использовать его в определенных сценариях.

Спасибо за просмотр!