Что происходит при падении master-узла в базе данных с репликацией?

Ответ

Падение master-узла — это критическое событие, которое запускает процесс восстановления доступности системы (failover).

Основные этапы:

  1. Остановка репликации: Slave-реплики перестают получать обновления от master-узла. Запись в базу данных становится невозможной.
  2. Обнаружение сбоя: Системы мониторинга (внешние или встроенные в кластер) фиксируют недоступность master-узла.
  3. Процесс выбора нового master (Failover):
    • Автоматический Failover: Специализированное ПО (например, Patroni для PostgreSQL, Orchestrator для MySQL) автоматически выбирает наиболее подходящую реплику и "повышает" её до нового master.
    • Ручной Failover: Администратор вручную выполняет команды, чтобы назначить одну из реплик новым master.
  4. Перенастройка топологии: Остальные slave-реплики перенастраиваются так, чтобы получать данные уже от нового master.
  5. Переключение клиентов: Приложения должны перенаправить свои запросы на запись на адрес нового 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-узел накрылся медным тазом — и понеслась пиздопроебищна на всю инфраструктуру. Ситуация, от которой волнение ебать, а терпения — ноль ебать.

Смотри, как это обычно бывает, ёпта:

  1. Репликация встала колом. Все slave-узлы такие: «Чувак, а где наши апдейты?». А писать-то в базу уже нихуя нельзя. Запись упёрлась в мёртвый master, как в стенку.

  2. Мониторинг охуел. Системы наблюдения, эти ядрёные воши, начинают орать: «Тревога, блядь! Master не дышит!». Либо софтина в кластере сама это чует.

  3. Выбор нового царя и бога (Failover). Тут два пути, оба — адреналин.

    • Автомат. Умная хрень типа Patroni или Orchestrator смотрит на реплики и говорит: «Ты, полупидор, будешь новым master-ом!». И повышает её. Красиво, если не сбоит.
    • Ручной. Админ, весь в поту, сука, бежит, руками тыкает команды, назначая нового повелителя. «Во все дыры давалка» в этот момент — это про него.
  4. Всех переподчиняют. Остальные slave-узлы, эти мартышлюшки, разворачиваются жопой к новому master-у и начинают с него данные сосать. Топология поменялась, всем похуй.

  5. Клиенты тупят. А приложения-то, хитрая жопа, всё ещё тычутся в старый, мёртвый адрес. Их надо пинком под жопу перенаправить на нового лидера. Вот тут-то и начинается веселье.

А как с этим жить в 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 о них нихуя не знает. Вот это и есть настоящая, чистая потеря данных. Сам от себя охуеешь, когда это обнаружишь. Так что доверия к такому процессу — ебать ноль, всегда надо быть начеку.