Ответ
Падение master-узла — это критическое событие, которое запускает процесс восстановления доступности системы (failover).
Основные этапы:
- Остановка репликации: Slave-реплики перестают получать обновления от master-узла. Запись в базу данных становится невозможной.
- Обнаружение сбоя: Системы мониторинга (внешние или встроенные в кластер) фиксируют недоступность master-узла.
- Процесс выбора нового master (Failover):
- Автоматический Failover: Специализированное ПО (например, Patroni для PostgreSQL, Orchestrator для MySQL) автоматически выбирает наиболее подходящую реплику и "повышает" её до нового master.
- Ручной Failover: Администратор вручную выполняет команды, чтобы назначить одну из реплик новым master.
- Перенастройка топологии: Остальные slave-реплики перенастраиваются так, чтобы получать данные уже от нового master.
- Переключение клиентов: Приложения должны перенаправить свои запросы на запись на адрес нового master-узла.
Как это обрабатывается в Go-приложении?
Наивный подход с попыткой переподключения в коде — плохая практика. Правильные архитектурные решения:
-
Использование прокси/балансировщика: Приложение подключается не напрямую к БД, а к прокси (например, PgBouncer, HAProxy), который отслеживает состояние кластера и автоматически направляет трафик на активный master-узел. Для приложения смена master-узла выглядит как кратковременный разрыв соединения.
-
Драйвер с поддержкой Failover: Некоторые драйверы баз данных позволяют указать в строке подключения несколько хостов. Драйвер сам будет пытаться подключиться к доступному master.
// Пример строки подключения для PostgreSQL // Драйвер попробует подключиться к host1, а в случае неудачи — к host2 connStr := "host=host1,host2 port=5432 user=user dbname=db sslmode=disable target_session_attrs=read-write" db, err := sql.Open("postgres", connStr)
Важный аспект: При асинхронной репликации возможна потеря транзакций, которые были успешно выполнены на старом master, но не успели реплицироваться на новый.
Ответ 18+ 🔞
А, ну это ж классика, блядь! Master-узел накрылся медным тазом — и понеслась пиздопроебищна на всю инфраструктуру. Ситуация, от которой волнение ебать, а терпения — ноль ебать.
Смотри, как это обычно бывает, ёпта:
-
Репликация встала колом. Все slave-узлы такие: «Чувак, а где наши апдейты?». А писать-то в базу уже нихуя нельзя. Запись упёрлась в мёртвый master, как в стенку.
-
Мониторинг охуел. Системы наблюдения, эти ядрёные воши, начинают орать: «Тревога, блядь! Master не дышит!». Либо софтина в кластере сама это чует.
-
Выбор нового царя и бога (Failover). Тут два пути, оба — адреналин.
- Автомат. Умная хрень типа Patroni или Orchestrator смотрит на реплики и говорит: «Ты, полупидор, будешь новым master-ом!». И повышает её. Красиво, если не сбоит.
- Ручной. Админ, весь в поту, сука, бежит, руками тыкает команды, назначая нового повелителя. «Во все дыры давалка» в этот момент — это про него.
-
Всех переподчиняют. Остальные slave-узлы, эти мартышлюшки, разворачиваются жопой к новому master-у и начинают с него данные сосать. Топология поменялась, всем похуй.
-
Клиенты тупят. А приложения-то, хитрая жопа, всё ещё тычутся в старый, мёртвый адрес. Их надо пинком под жопу перенаправить на нового лидера. Вот тут-то и начинается веселье.
А как с этим жить в Go, спросишь ты?
Слушай сюда, самый нативный подход — тупо пытаться переподключиться в коде — это пиздец какой кринж. Не делай так, а то будешь выглядеть, как манда с ушами.
Нормальные люди делают так:
-
Прокси/балансировщик — твой лучший друг. Ты в приложении подключаешься не к самой базе, а к какой-нибудь прослойке, типа PgBouncer или HAProxy. Эта хитрая жопа сама знает, где сейчас живой master, и направляет трафик туда. Для твоего кода failover будет выглядеть как мелкий ик — соединение на секунду порвалось и восстановилось. Красота, ёперный театр!
-
Умный драйвер. Некоторые драйверы уже не лыком шиты. Ты можешь в строке подключения накидать несколько хостов, а он сам будет шерстить их, ища того, кто на запись отвечает.
// Для PostgreSQL, например. Драйвер попробует host1, а если тот сдох — полезет на host2. connStr := "host=host1,host2 port=5432 user=user dbname=db sslmode=disable target_session_attrs=read-write" db, err := sql.Open("postgres", connStr)
И главный подвох, блядь, о котором все забывают! Если репликация была асинхронная (а она часто такая), то есть риск потерять те транзакции, которые старый master успел принять, но не успел выплюнуть на реплики. Новый master о них нихуя не знает. Вот это и есть настоящая, чистая потеря данных. Сам от себя охуеешь, когда это обнаружишь. Так что доверия к такому процессу — ебать ноль, всегда надо быть начеку.