Две стороны Meituan: как обеспечить согласованность двойной записи Redis и MySQL?

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

предисловие

В апреле друг пошел в Meituan на собеседование, он сказал, что его спросили, как обеспечить согласованность двойной записи между Redis и MySQL? Этот вопрос на самом деле спрашивает, как гарантируется согласованность кеша и базы данных в сценарии с двойной записью? В этой статье мы обсудим с вами, как ответить на этот вопрос.

Разговор о постоянстве

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

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

Три классических режима кэширования

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

  • Cache-Aside Pattern
  • Read-Through/Write through
  • Write behind

Cache-Aside Pattern

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

Cache-Aside процесс чтения

Cache-Aside PatternПроцесс запроса на чтение выглядит следующим образом:

Cache-Aside读请求

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

Процесс записи в кэш-память

Cache-Aside PatternПроцесс запроса на запись выглядит следующим образом:

Cache-Aside写请求

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

Сквозное чтение/запись

Read/Write ThroughВ режиме сервер использует кеш в качестве основного хранилища данных. Приложение взаимодействует с кэшем базы данных черезабстрактный слой кэшаЗаконченный.

Read-Through

Read-ThroughКратко процесс выглядит следующим образом

Read Through简要流程

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

Следует ли этот краткий процессCache-Asideочень похожий? фактическиRead-Throughпросто еще один слойCache-Provider, процесс выглядит следующим образом:

Read-Through流程

Read-Through на самом деле простоCache-AsideНа нем выполняется слой инкапсуляции, что делает программный код более лаконичным и снижает нагрузку на источник данных.

Write-Through

Write-Throughрежиме, когда происходит запрос на запись, он такжеуровень абстракции кэшаПроцесс обновления источника данных и кэшированных данных выглядит следующим образом:Write-Through流程

Запись позади (асинхронная запись в кеш)

Write behindиRead-Through/Write-ThroughЕсть сходства, как поCache ProviderОтвечать за чтение и запись кеша и базы данных. Между ними есть большая разница:Read/Write Throughзаключается в синхронном обновлении кеша и данных,Write BehindИменно для обновления кеша, а не для обновления базы данных напрямую, черезпакетный асинхронныйспособ обновления базы данных.

Write behind流程

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

При работе с кешем вы удаляете кеш или обновляете кеш?

В общих бизнес-сценариях мы используемCache-Asideмодель. Некоторые друзья могут спросить,Cache-AsideПри написании запроса, почему этоУдалить кеш вместо обновления кешаШерстяная ткань?

Cache-Aside写入流程

Когда мы работаем с кешем, должны ли мы удалять кеш или обновлять кеш? Сначала рассмотрим пример:

  1. Поток A сначала инициирует операцию записи, и первым шагом является обновление базы данных.
  2. Поток B инициирует другую операцию записи, а второй шаг обновляет базу данных.
  3. Из-за сетевых и других причин поток B сначала обновил кеш.
  4. Поток A обновляет кеш.

В это время в кэше хранятся данные A (старые данные), в базе данных хранятся данные B (новые данные), а данныенепоследовательныйТеперь появляются грязные данные. еслиУдалить кэш вместо обновления кешаЭта проблема с грязными данными не возникнет.

Обновление кеша или удаление кеша, есть два недостатка:

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

В случае двойной записи вы сначала работаете с базой данных или с кешем?

Cache-AsideВ режиме кеша у некоторых знакомых еще есть сомнения, зачем он при написании запроса?Как насчет работы с базой данных в первую очередь?? ПочемуНе работайте с кешем в первую очередьШерстяная ткань?

Предположим, есть два запроса, A и B. A запрашивается выполнение операции обновления, а B запрашивается выполнение операции запроса и чтения.image.png

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

Есть проблема с фиолетовым соусом,Данные кэша и базы данных несовместимы. Кэш хранит старые данные, база данных хранит новые данные. следовательно,Cache-AsideРежим кеша: сначала выберите работу с базой данных, а не с кешем.

Кэш задерживает двойное удаление

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

image.png

  1. сначала удалите кеш
  2. Обновите базу данных еще раз
  3. Переждите некоторое время (например, 1 секунду) и снова удалите кеш.

Этот сон на некоторое время, вообще как долго? Это все 1 секунда?

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

Удалить механизм повторных попыток кеша

не важно какОтсроченное двойное удалениевсе ещеCache-Aside сначала обрабатывает базу данных, а затем удаляет кеш, если удаление кеша на втором шаге не удастся, ошибка удаления приведет к грязным данным~

Если удаление не удалось, удалите его несколько раз, чтобы убедиться, что удаление кеша прошло успешно ~ Таким образом, его можно ввестиУдалить механизм повторных попыток кеша

image.png

  1. написать запрос на обновление базы данных
  2. Удаление кеша не удалось по какой-то причине
  3. Поместите ключ, который не удалось удалить, в очередь сообщений
  4. Использовать сообщение очереди сообщений и получить ключ для удаления
  5. Повторите операцию удаления кеша.

Читать biglog асинхронно удалять кеш

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

image.png

Взяв в качестве примера mysql, вы можете использовать канал Ali для отправки коллекции журналов binlog в очередь MQ, а затем подтвердить обработку сообщения об обновлении через механизм ACK, удалить кеш и обеспечить согласованность кеша данных.

Ссылка и спасибо