Прямой ответ
Split brain — состояние, при котором кластер разделяется на две (или более) группы, каждая из которых считает себя работоспособной и продолжает принимать запись. Итог — расходящиеся версии одних и тех же данных, которые потом приходится разбирать вручную. Классическая причина — сетевое разделение (partition): узлы живы, но не видят друг друга.
Почему это вообще возможно:
- Чётное число узлов. При
N=2каждая половина «думает», что она и есть большинство, либо блокируется полностью — отказоустойчивости нет. - Отсутствие кворума в решении. Если роль лидера определяется локально («я не получил heartbeat, значит я лидер»), разделение обязательно даст двух лидеров.
- Опора только на TTL. Аренда без fencing не мешает «воскресшему» лидеру писать после того, как его роль уже передана.
Защиты, работающие в комплексе:
- Кворум (большинство). Любое решение требует подтверждения большинства узлов — при разделении победить может только одна сторона. Это основа Raft и Paxos.
- Нечётное число участников и witness. Три узла в трёх зонах; при потере одной зоны остаются два из трёх — кворум цел. Witness — лёгкий участник, который голосует, но не хранит данные.
- Fencing / STONITH. Изоляция бывшего лидера: отзыв доступа через токены, отключение сети или выключение узла. Без этого кворум защищает только решение, но не данные.
- Явная деградация меньшинства. Меньшая сторона обязана переходить в read-only или полностью отказывать в записи, а не «работать как ни в чём не бывало».
Практика: симптомы и быстрая диагностика
Как выглядит инцидент:
- два узла сообщают
role: leaderодновременно; - клиент получает разные ответы в зависимости от того, на какой узел попал;
- после «схлопывания» сети часть записей исчезает или конфликтует;
- метрика смен лидера растёт лавинообразно.
Команды для etcd-кластера:
# состояние участников и лидерство
etcdctl endpoint status --cluster -w table
# кто сейчас лидер и какой терм
etcdctl endpoint status -w json | jq '.[].Status.leader, .[].Status.raftTerm'
# здоровье участников
etcdctl endpoint health --cluster
Если endpoint status --cluster отвечает только с части узлов, а остальные возвращают context deadline exceeded — это признак разделения, а не «медленного диска».
Для Patroni: patronictl list показывает лидера и lag реплик; отсутствие лидера при живых узлах обычно означает потерю связности с DCS. Разбор механики — в статье про failover PostgreSQL и Patroni.
Что проверить по порядку:
- Связность между узлами (не только «сеть вообще», а именно mesh между участниками).
- Время на узлах: рассинхронизация ломает TTL-аренды и логи с временными метками.
- Задержки диска: долгий fsync выглядит как потеря кворума и запускает перевыборы.
- Лимиты и CPU-throttling в Kubernetes: узел может «молчать» из-за троттлинга, а не из-за сети — про поды и ресурсы см. основы Kubernetes.
Практический сценарий: разделение зоны в PostgreSQL-кластере
Контекст: Patroni + etcd, три узла: два в зоне A, один в зоне B. Потеряна связность между зонами.
- Что происходит. В зоне A остаются два etcd-узла — кворум есть, лидер etcd сохраняется, текущий лидер PostgreSQL продолжает работу. Узел в зоне B теряет связь с DCS, его ключ лидера/реплики истекает, и он обязан уйти в read-only.
- Опасный сценарий. Если бы узлы были 2/2 (по одному в каждой зоне), обе стороны потеряли бы кворум etcd — кластер стал бы недоступен для записи, но зато без расхождения данных. Хуже вариант, когда promote выполняется «вручную» без DCS: тогда появляются два writable-узла.
- Действия дежурного. Убедиться, что меньшинство действительно read-only (
pg_is_in_recovery()возвращаетtrue), не выполнять ручной promote до восстановления связности, зафиксировать timeline. - Восстановление. После возвращения сети узел B догоняет лидера; при расхождении timeline требуется
pg_rewindили пересоздание реплики. - Постмортем. Проверяем, что witness/третий узел живёт в третьей зоне, а не «для галочки» в той же стойке; добавляем алерт на потерю кворума и на
pg_is_in_recovery()у неожиданного узла. Как оформлять разбор — в статье про incident management и runbook.
Результат: данные не разошлись, потому что меньшинство деградировало штатно. Вывод: защита от split brain — это топология (нечётное число, разные зоны) плюс явное поведение меньшинства плюс fencing, а не один параметр в конфиге.
Чек-лист перед тем, как объявить инцидент закрытым. Убедитесь, что в кластере ровно один лидер и его терм/ревизия совпадают на всех узлах; что реплики в меньшинстве действительно не принимали запись (проверьте счётчики записей и timeline); что после восстановления связности не осталось «сиротских» данных, которые придётся удалять вручную; и что изменения конфигурации, предотвращающие повтор, зафиксированы в коде инфраструктуры, а не только в чате дежурных. Без этих четырёх пунктов инцидент считается незакрытым, даже если сервис уже отвечает на запросы.
FAQ
Можно ли полностью исключить split brain? Нельзя исключить само разделение сети — оно физически возможно всегда. Можно сделать его безопасным: кворум гарантирует, что запись принимает только одна сторона, а fencing гарантирует, что бывший лидер не сможет испортить данные. Теоретическая рамка этого компромисса описана в статье про теорему CAP.
Почему не подходит чётное число узлов? Для четырёх узлов кворум равен трём: отказ одного узла оставляет три (работает), но устойчивость та же, что у трёх узлов, а задержка записи выше. При делении 2/2 обе стороны блокируются — доступность теряется без выигрыша в безопасности.
Что такое STONITH и нужен ли он в облаке? STONITH — «Shoot The Other Node In The Head», аппаратная изоляция узла. В облаке прямой аналог — принудительное выключение инстанса через API или отзыв сетевых правил. Суть та же: бывший лидер должен потерять физическую возможность писать, а не только «перестать считать себя лидером».
Как понять, что fencing действительно работает? Проведите учебный инцидент: остановите лидера на уровне процесса, дождитесь перевыборов, затем верните процесс и попробуйте записать данные. Запись должна быть отклонена. Механику лидерства и токенов см. в статье про выборы лидера.
Источники: etcd docs (failures), Patroni docs, Wikipedia (split-brain) — ссылки в шапке.