Как сохранить согласованность данных в mysql и redis?

задняя часть MySQL

1. Описание блок-схемы

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

在这里插入图片描述

2. Вопросы

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

3. Обновление стратегии

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

Против этого плана обычно все возражают. Зачем? Этому есть две причины.

3.1.1 Причина 1 (потокобезопасность)

При этом есть запрос А и запрос Б на операции обновления, тогда будет

  • 1) Thread A обновляет базу данных
  • 2) Поток B обновляет базу данных
  • 3) Поток B обновляет кеш
  • 4) Thread A обновляет кеш

Это означает, что запрос A на обновление кеша должен быть отправлен раньше, чем запрос B на обновление кеша, но из-за сетевых и других причин B обновил кеш раньше, чем A. Это приводит к грязным данным, поэтому они не учитываются.

3.1.2 Причина 2 (перспектива бизнес-сценария)

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

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

接下来讨论的就是争议最大的,先删缓存,再更新数据库。还是先更新数据库,再删缓存的问题。

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

Программа вызывает несоответствия, потому что. В то же время есть запрос A на операцию обновления и другой запрос B на операцию запроса. Тогда произойдет следующая ситуация:

  • 1) Запрос A на выполнение операции записи и удаление кеша
  • 2) Попросите B запросить и обнаружить, что кеш не существует.
  • 3) Запросите B запросить базу данных, чтобы получить старое значение
  • 4) Запросить B записать старое значение в кеш
  • 5) Запрос A для записи нового значения в базу данных

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

Итак, как это решить? Используйте стратегию отложенного двойного удаления

/**
*解决方法的伪代码
*/
public void write(String key,Object data){
	//1、先删除缓存
	redis.delKey(key);
	//2、更新数据库,写入数据
	db.updateData(data);
	//3、休眠1秒
	Thread.sleep(1000);
	//4、再次删除缓存
	redis.delKey(key);

}

3.2.1 Как определить время сна?

Итак, как определяется эта 1 секунда, и как долго она должна спать?

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

Конечно, эта стратегия также учитывает трудоемкую синхронизацию Redis и базы данных master-slave. Время последнего сна для записи данных: добавьте несколько сотен мс к трудоемкой бизнес-логике чтения данных. Например: спать в течение 1 секунды.

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

Во-первых, давайте поговорим об этом. Иностранцы предложили процедуру обновления кеша под названием《Шаблон кэширования》. что указывает

  • Инвалидация: приложение сначала извлекает данные из кеша, если не получается, то извлекает данные из базы данных и после успеха помещает их в кеш.
  • Попадание: приложение извлекает данные из кеша и возвращает после извлечения.
  • Обновление: сначала сохраните данные в базе данных, а затем аннулируйте кеш после успеха.

Кроме того, в статье также фигурирует известная социальная сеть facebook.«Масштабирование Memcache в Facebook»Предлагается, чтобы они также использовали стратегию сначала обновления базы данных, а затем удаления кеша.

/**
*解决方法的伪代码
*/
public void write(String key,Object data){
	//1、更新数据库,写入数据
	db.updateData(data);
	//2、删除缓存
	redis.delKey(key);
}

3.3.1 Нет ли в этой ситуации проблемы параллелизма?

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

  • 1) Кэш просто не работает
  • 2) Запросите A, чтобы запросить базу данных и получить старое значение
  • 3) Запросить B записать новое значение в базу данных
  • 4) Запрос Б на удаление кеша
  • 5) Запрос A записать старое найденное значение в кеш

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

3.3.2 Какова вероятность проблемы параллелизма?

Вышеупомянутая ситуация имеет врожденное условие, то есть операция записи базы данных на шаге (3) занимает меньше времени, чем операция чтения базы данных на шаге (2), так что можно сделать шаг (4) предшествующим шагу (5). . Однако подумайте об этом, скорость операции чтения базы данных намного выше, чем скорость операции записи (иначе, зачем делать разделение чтения-записи, значение разделения чтения-записи заключается в том, что операция чтения выполняется быстрее и потребляет меньше ресурсов), поэтому шаг (3) занимает меньше времени, чем шаг (2), и эту ситуацию трудно реализовать.

3.3.3 Как решить вышеупомянутую проблему параллелизма?

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

4. Обсуждение лучшего решения

4.1 Вариант 1

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

4.2 Вариант 2

Срок действия данных в Redis не всегда истекает, но есть задача фонового обновления («код выполнения по времени» или «код, управляемый очередью»), который считывает базу данных и загружает последние данные в Redis. Этот подход рассматривает Redis как «хранилище» . Посетитель не знает фактический источник данных, стоящий за ним, но знает только, что Redis — единственное место для получения данных. Когда фактический источник данных обновляется, задача фонового обновления используется для обновления данных в Redis. время, все еще будет Redis и проблема несоответствия фактических источников данных, если это запланированная задача, самая большая продолжительность несоответствия - это интервал выполнения задачи обновления, если она обновляется способом, аналогичным очереди, время несоответствия зависит от задержки формирования очереди и потребления.Обычно используемые очереди (или эквивалентные) есть Redis (как же все-таки Redis), Kafka, AMQ, RMQ, binglog, файлы логов, канал Али и т.д.

5. Ссылки

Ууху. Call.com/question/31… zhuanlan.zhihu.com/p/98909029