Продолжим разбирать репликацию по 5-й главе кабанчика («Высоконагруженные приложения» Мартина Клепманна).
В прошлом посте начали обсуждение репликации с одним ведущим узлом (лидером): запросы на запись поступают только к лидеру, а запросы на чтение могут направляться как к лидеру, так и к любой реплике. Чем больше реплик — тем больше запросов на чтение можно обработать.
Такая архитектура называется масштабируемой по чтению (read-scaling architecture).
Если асинхронная реплика запаздывает, то при одинаковом запросе к лидеру и реплике мы можем получить разные данные, поскольку еще не все операции записи успели реплицироваться. Такая несогласованность временна: если прекратить запись в БД и немного подождать, то все реплики наверстают упущенное и окажутся согласованными с лидером. Поэтому такой эффект
называется конечной согласованностью (eventual consistency).
Проблемы при задержке репликации
▶️Возьмем стандартный сценарий: пользователь редактирует свой профиль на сайте — запрос на запись поступает лидеру. Затем пользователь обновляет страницу — запрос на чтение поступает реплике, до которой еще не дошли новые данные. Пользователь не видит своих изменений и расстраивается.
Для исключения таких ситуаций используется подход read-your-writes (чтение своих записей).
Есть несколько способ реализации этого подхода:
🟢 данные профиля обычно может редактировать только сам пользователь, поэтому их всегда можно читать с лидера
🟢 отслеживать время последнего обновления и в течение одной минуты после этого читать все с лидера
🟢 на клиенте запоминать метку даты/времени своей последней операции записи — если реплика, на которую поступил запрос, недостаточно актуальна, то можно делегировать операцию чтения другой реплике
▶️Рассмотрим другой сценарий. Пользователь активно спорит в комментариях. Благодаря подходу read-your-writes свои комментарии у него всегда видны. А вот свежий комментарий оппонента только что был виден — запрос на чтение был обработан актуальной репликой, а после обновления страницы пропал — повторный запрос был обработан другой репликой, которая отстает сильнее, и на нее комментарий оппонента еще не реплицировался. Только наш пользователь отправил «ага, удаляешь комментарии!», как комментарий оппонента вновь появился. Эта особенность точно добавит перца в дискуссию.
Для предотвращения такой ситуации нужна гарантия монотонного чтения записей. Она означает, что старые данные не будут читаться после новых.
Один из способов реализации монотонного чтения записей — обеспечить чтение данных одним пользователем из одной и той же реплики. Например, можно выбирать реплику не случайным образом, а на основе хеша идентификатора пользователя.
▶️Продолжим пример с дискуссией.
Анна: «Борис, у вас есть скрам-мастер?»
Борис: «Нет, у нас нет скрам-мастеров»
Если база данных разделена на несколько шардов, которые функционируют независимо, то упорядочивания операций записи между ними нет. Допустим, вопрос Анны записался на один шард, а ответ Бориса — на другой. Если реплика узла с ответом Бориса имеет небольшую задержку, а у реплики узла с вопросом Анны задержка больше, то наблюдатель дискуссии может увидеть следующее:
Борис: «Нет, у нас нет скрам-мастеров»
Анна: «Борис, у вас есть скрам-мастер?»
Для предотвращения подобных аномалий необходимо обеспечить гарантию согласованного префиксного чтения (consistent prefix reads). Она означает, что если операции записи выполняются в определенной последовательности, то
в ней же они будут и прочитаны.
Одно из решений — все операции записи, связанные друг с другом, сохранять в один шард, но в ряде приложений сделать это эффективно невозможно. Существуют также алгоритмы явного отслеживания причинно-следственных связей, они рассматриваются подробнее в разделе репликации без лидера.
#кабанчик #сисдиз
Post #58
1.95K
- 🔥 9
- 👍 5
- ❤ 3