В интервью всегда так.
1. Анализ сценариев
Интервьюер: Каков QPS вашего сервиса?
Я: В пиковый период работы нашего сервиса количество посещений достаточно большое, около 30 000.
Интервьюер: Может ли ваш сервер поддерживать такой большой объем трафика? Кэш есть?
Я: Да, мы используем Redis в качестве кеша, интерфейс сначала запрашивает кеш, а доступ к базе данных осуществляется только тогда, когда кеша не существует. Это может снизить нагрузку на доступ к базе данных и повысить эффективность запросов.
Интервьюер: Часть данных хранится в двух местах. При обновлении данных, как вы обеспечиваете согласованность данных?
Как видите, хорошие интервьюеры обычно не спрашивают вас напрямую о решении проблемы согласованности данных, а следуют хорошему руководству в сочетании с конкретными сценариями использования, а затем спрашивают вас о решениях. Если вы этого не делали и не имеете практического опыта работы в сети, то вообще сложно ответить рационально и вдумчиво.
Обычно существует четыре метода обеспечения согласованности данных:
- Сначала обновите кеш, а затем обновите базу данных.
- Сначала обновите базу данных, а затем обновите кеш.
- Сначала удалите кеш, а затем обновите базу данных.
- Сначала обновите базу данных, а затем удалите кеш.
Подробно рассматривается каждый вариант:
2. Решения
2.1 Сначала обновите кеш, затем обновите базу данных
Если одновременно приходят два одновременных запроса на запись, процесс выполнения выглядит следующим образом:
- Напишите запрос 1 для обновления кеша, установите возраст равным 1
- Напишите запрос 2 для обновления кеша, установите возраст равным 2
- Напишите запрос 2 для обновления базы данных, установите возраст 2
- Напишите запрос 1 для обновления базы данных, установите возраст равным 1
Результатом выполнения является то, что возраст в кеше установлен на 2, а возраст в базе данных установлен на 1, что приводит к несогласованности данных.Это решение невозможно.
2.2 Сначала обновите базу данных, затем обновите кеш
Если одновременно приходят два одновременных запроса на запись, процесс выполнения выглядит следующим образом:
- Напишите запрос 1 для обновления базы данных, установите возраст равным 1
- Напишите запрос 2 для обновления базы данных, установите возраст 2
- Напишите запрос 2 для обновления кеша, установите возраст равным 2
- Напишите запрос 1 для обновления кеша, установите возраст равным 1
Результатом выполнения является то, что возраст в базе данных установлен на 2, а возраст в кэше установлен на 1, что приводит к несогласованности данных.Это решение невозможно.
2.3 Сначала удалите кэш, затем обновите базу данных
Если одновременно приходят два одновременных запроса на чтение и запись, процесс выполнения выглядит следующим образом:
- Запрос на запись удаляет кеш
- В кеше запроса запроса на чтение нет данных, затем запросите базу данных, а затем запишите данные в кеш.
- написать запрос на обновление базы данных
Результатом выполнения является то, что старые данные находятся в кеше, а новые данные находятся в базе данных, что приводит к несогласованности данных.Это решение невозможно.
2.4 Сначала обновите базу данных, затем удалите кеш
Эта схема не вызовет проблем при параллельной записи. Поскольку сначала обновляется база данных, а затем удаляется кеш, несогласованности не будет.
Однако при одновременном чтении и записи может возникнуть несогласованность данных.
- В кеше запроса запроса на чтение нет данных, а затем запросите базу данных
- Написать запрос на обновление базы данных, удалить кеш
- Кэш обратной записи запроса на чтение
Результатом выполнения является наличие старых данных в кэше и новых данных в базе данных, что приводит к несогласованности данных.
На самом деле вероятность такой ситуации очень мала.Кэш записи на несколько порядков быстрее, чем запись БД.Кэши чтения и записи - это все операции с памятью, и скорость очень высокая.
В этом экстремальном сценарии нам также нужно выполнить восходящее решение, и кеш должен установить время истечения срока действия. Эта схема относится к слабой согласованности и согласованности данных в конечном итоге, а не к строгой согласованности.
3. Резюме и размышления
Некоторым читателям может быть любопытно, почему бы не добавить аннотации транзакций для обновления методов кэша и базы данных, чтобы добиться строгой согласованности, чтобы не было проблем ни с одной из схем.
Да, добавление локальных транзакций возможно, когда наш сервис только на одной машине. Однако на работе мы будем развертывать сервис на десятках или сотнях машин.Иногда, чтобы справиться с более экстремальными запросами, мы добавляем слой локального кеша в кеш Redis.В настоящее время мы должны использовать локальные транзакции снова?
Часть данных существует на нескольких машинах и имеет несколько копий.Для достижения строгой согласованности мы также можем использовать распределенные транзакции. Таким образом, операция обновления кэша станет очень сложной, а выигрыш перевесит выигрыш.
Однако в других сценариях, таких как обновление статуса заказа и обновление пользовательских активов, в этом сценарии мы должны добиться строгой согласованности данных независимо от того, сколько мы платим.Конкретные схемы реализации обычно включают следующее:
- двухэтапная фиксация
- TCC
- локальная таблица сообщений
- Сообщение транзакции MQ
- ПО промежуточного слоя для распределенных транзакций
В следующей статье мы подробно разберем преимущества и недостатки этих решений.