🕒🔄 Векторные часы: как синхронизировать две мастер-базы без потери данных
Синхронизация двух мастер-баз кажется сложной задачей? Векторные часы предлагают простое решение. Этот подход обеспечивает согласованность данных в распределенных системах, повышая надежность и эффективность вашей IT-инфраструктуры.
Потребность в синхронизации баз данных возникает нередко – и чаще всего это связано с переходом с устаревшей системы на современную технологию. Иногда оба приложения вместе с их собственными базами данных должны работать параллельно в течение длительного периода, поскольку демонтаж процессов, зависящих от устаревшей системы, не представляется возможным. Следовательно, необходимы специальные решения для поддержания двух основных баз данных в согласованном состоянии, чтобы все операции в первой базе данных зеркально отражались во второй, и наоборот. Авторы этой публикации столкнулись именно с таким нетривиальным кейсом:
- Старое приложение должно было работать параллельно с новым в течение длительного времени, чтобы сотрудники компании имели возможность постепенно перевести все процессы на новую версию.
- Если в процессе перехода одно приложений оказывалось недоступным, другое обязательно должно было продолжать работу.
- Обе базы данных работали с одним и тем же набором данных, но с разными схемами: например, клиент в одной базе данных был представлен с помощью другого количества таблиц и столбцов по сравнению со второй.
- Для синхронизации баз данных не существовало готового CDC-решения.
- Устаревшее приложение поддерживало синхронизацию только с помощью асинхронных сообщений.
С учетом этих ограничений разработчики пришли к решению, которое обеспечило синхронизацию данных между двумя различными системами, сохраняя их независимость и устойчивость к сбоям:
- Было решено использовать двунаправленную асинхронную передачу сообщений, управляемую на уровне приложения, для обмена данными между двумя мастер-базами. Также был реализован одинаковый алгоритм синхронизации с обеих сторон.
- Каждая мастер-база публикует событие выравнивания, которое содержит полный набор данных, соответствующий последнему изменению.
- Для обработки событий с обеих сторон используется алгоритм векторных часов.
Асинхронная коммуникация и общий алгоритм
Для обмена сообщениями в обоих направлениях были использованы две очереди Kafka. Схема Avro была сохранена идентичной для обеих очередей, поэтому события также были идентичны по формату. Такое решение позволило создать общий абстрактный слой для обеих мастер-баз, который не зависит от конкретных технологий, а опирается только на алгоритм выравнивания и общую модель данных, используемой для событий. Основные преимущества этого подхода:
- Отделение модуля выравнивания от реализации двух мастер-баз. Это дает возможность разрабатывать, изменять и улучшать архитектуру и функциональность модуля выравнивания независимо от основных систем.
- Обеспечение независимой работы двух мастер-баз. Если одна мастер-база перестает работать, другая может продолжать функционировать.
- Опора на алгоритм обеспечивает независимость от конкретной технологии. Корректность реализации алгоритма всегда можно проверить специальными тестами. В долгосрочной перспективе это приводит к стабильному решению с малой подверженностью ошибкам.
Ценой этих преимуществ, однако, является необходимость реализации алгоритма в обоих приложениях.
Упорядочивание сообщений
Главное требование при синхронизации баз данных – это механизм, который позволяет упорядочивать сообщения независимо от того, в какой системе они были созданы. Это важно для сохранения целостности и согласованности данных в распределенных средах.
Существует два типа упорядочивания
- Полное упорядочивание – позволяет расположить все сообщения в определенной последовательности, давая полный обзор событий в системе.
- Частичное упорядочивание – позволяет упорядочить только часть сообщений, что дает гибкость в соотнесении событий.
Были рассмотрены разные решения для упорядочивания сообщений:
Серверные часы
- Плюс – простота использования.
- Минусы – возникают вопросы о том, часы какого сервера использовать, как их синхронизировать, что делать при рассинхронизации, как учесть особенности инфраструктуры и компонентов каждого приложения.
Выделенные централизованные логические часы
- Плюс – единая точка отсчета времени для всей системы.
- Минус – может создавать узкие места и точки отказа, что не подходит для распределенных масштабируемых систем.
Распределенные логические часы (векторные)
Плюсы:
- Позволяют осуществлять как полное, так и частичное упорядочивание без единой точки отказа.
- Каждая часть системы имеет свои часы, которые обновляются при появлении новых сообщений или изменении данных.
- Хорошо подходят для управления сложными распределенными системами, помогая разрешать конфликты и эффективно синхронизировать данные.
Как работают векторные часы: особенности алгоритма
Для каждой записи в базе данных каждая система ведет свои собственные внутренние логические часы, а также хранит информацию о часах другой базы данных, полученную из очереди синхронизации. На иллюстрации они представлены столбцами Clock A и Clock B:
В этом примере Мастер A изменяет запись и увеличивает значение своих Часов A. Мастер B получает запись и сравнивает два значения часов. Часы B равны 0 и совпадают, в то время как Часы A были увеличены. Поэтому Мастер B принимает сообщение и перезаписывает свою запись, синхронизируя ее с записью Мастера A. Затем Мастер B выполняет аналогичное изменение той же записи, увеличивая свои Часы B. Мастер A получит сообщение, и поскольку Часы A остались прежними, он может принять сообщение и синхронизировать запись.
Существует вероятность конфликта, когда изменение одной и той же записи происходит одновременно в обеих системах. В этом случае обе системы получают сообщение о синхронизации, где их собственные часы меньше, чем те, что хранятся в данный момент. Хотя такой сценарий считается редким, нужно определить, как разрешать конфликт. Возможны различные решения: например, можно решить, что в случае конфликта один из двух мастеров всегда «побеждает», то есть является «более главным», чем другой. Или, как было решено в данном случае, можно использовать метки времени для определения последней записи. Авторы осознают, что использование меток времени для определения порядка может быть проблематичным, но вероятность конфликта (т.е. обновления одних и тех же данных в обеих системах за короткий промежуток времени) считается очень низкой (менее 0.1%). В этом сценарии метка времени события также должна быть отправлена в сообщении о синхронизации.
Итоги кейса
В контексте этого кейса векторные часы стали оптимальным решением – они позволили каждой части системы независимо отслеживать время, и при этом обеспечили механизм для согласования времени между различными компонентами. Реализация была достаточно сложной:
- Необходимо было внести изменения в структуру и функционирование обеих баз данных для поддержки этого метода синхронизации.
- Все запросы на запись нужно было модифицировать для атомарного управления векторными часами – обновление данных и соответствующих векторных часов происходило как единая, неделимая операция.
- Алгоритм синхронизации надо было реализовать на обеих сторонах.
Хотя это решение потребовало значительных усилий по реализации и поддержке, оно было оправдано, поскольку успешно учитывало все ограничения, а преимущества от такой синхронизации значительно перевешивали все сложности.