Обеспечение высокой доступности — это база для любого Enterprise-решения. В экосистеме Postgres Pro за это отвечает BiHA (Built-in High Availability). Это не просто внешняя «обвязка» вроде Patroni, а глубоко интегрированное в ядро Postgres Pro Enterprise решение. Оно работает «из коробки», управляется через SQL-интерфейс и утилиту bihactl. За выборы нового лидера отвечает алгоритм Raft: при сбое узлы голосуют и однозначно определяют единственного победителя, не допуская ситуации, когда пишущих узлов становится два.

BiHA поддерживала работу с несколькими ЦОДами и раньше, однако с появлением каскадной репликации геораспределённые инсталляции стали значительно эффективнее. Но современные требования бизнеса — катастрофоустойчивость: работа в нескольких дата-центрах (ЦОД), разнесённых на сотни километров. С выходом каскадной репликации BiHA официально выходит на уровень глобальных инсталляций, решая проблемы сетевой нагрузки и масштабируемости.

Коротко о BiHA

BiHA (Built-in High Availability) — это встроенное решение Postgres Pro, которое превращает несколько серверов в отказоустойчивый кластер. В отличие от Patroni и других внешних решений, BiHA работает как отдельный процесс внутри экземпляра Postgres, управляется утилитой bihactl и SQL-функциями, а выборы лидера проводит по алгоритму Raft, без риска Split-Brain.

Ключевые возможности, которые уже оценили пользователи начиная с Postgres Pro Enterprise 16:

  • автоматическое переключение лидера при сбое без участия администратора;

  • легковесный узел-рефери для обеспечения кворума без хранения пользовательских данных;

  • параметр can_be_leader=false для узлов, которые не могут быть выбраны лидером;

  • пользовательские колбэки (callbacks) — SQL-функции, вызываемые при изменении топологии кластера;

  • поддержка кворумной синхронной и асинхронной репликации.

Теперь к этому списку добавилась каскадная репликация.

Проблема: «звезда» не вписывается в географию

В классической схеме кластера BiHA все реплики (Follower) подключаются напрямую к Лидеру. Это выглядит логично, когда узлы находятся в одном дата-центре. Но когда кластер разнесён на несколько ЦОДов, такая «звёздная» топология превращается в источник боли.

Что происходит при двух-трёх ЦОДах:

  • Лидер передаёт одни и те же WAL-сегменты каждому узлу в удалённом ЦОДе по отдельности. Если в резервном ЦОДе стоят три реплики, один и тот же поток данных уходит в него трижды.

  • Межцодовый канал — дорогой и ограниченный ресурс. При больших объёмах изменений он может стать узким местом всей системы.

  • Лидер тратит walsender-процессы на каждого подписчика: при 10 репликах — 10 walsender, при 20 — 20. Это прямые накладные расходы на CPU и память.

Крупные заказчики хотят одновременно двух вещей: защиты от падения основного ЦОДа с геораспределённым кластером и минимизации трафика между площадками. С классической «звездой» эти требования сложно выполнить. Каскадная репликация решает именно этот конфликт.

Решение: граф репликации как дерево

Идея каскадной репликации проста: не все реплики обязаны получать WAL напрямую от Лидера. Часть реплик может реплицироваться от других реплик, образуя дерево, где Лидер является корнем, а промежуточные узлы одновременно принимают WAL и раздают его «вниз».

Представьте такую схему для двух ЦОДов:

ЦОД 1:  Лидер (БД1)
           │
        Реплика (БД2) ←── синхронная реплика, локальная
           │
ЦОД 2:  Реплика-ретранслятор (БД3)  ←── получает WAL от БД2
           │
        Реплика (БД4) ←── получает WAL от БД3

Теперь из ЦОДа 1 в ЦОД 2 идёт только один поток WAL — на БД3. А БД3 уже раздаёт его локально внутри резервного ЦОДа. Трафик между площадками сокращается кратно числу реплик во втором ЦОДе.

Технически: как устроено дерево репликации

Граф репликации в BiHA — это ориентированное дерево: без петель, с единственным корнем-Лидером, от которого расходятся все ветки.

Алгоритм Best Follower

Узлы не просто подключаются к первому доступному источнику, а выбирают наиболее подходящий. Алгоритм Best Follower работает так:

  1. Перед принятием решения узел выдерживает таймаут, который зависит от его приоритета.

  2. Узел получает список доступных для подключения узлов.

  3. Из них он выбирает лучший источник, руководствуясь предпочитаемыми ролями (pref_roles) и сравнением LSN (Log Sequence Number): выбирается тот, у кого данные свежее.

Предпочтение можно настроить: например, pref_roles=FL означает «сначала пробуй подключиться к Follower, затем — к Лидеру». Это позволяет снять нагрузку с Лидера там, где это возможно, не жертвуя актуальностью данных.

Новые параметры конфигурации

Для управления каскадной репликацией в BiHA появились два новых параметра на уровне узла:
 

max_ws (max walsenders)

Ограничивает, скольким репликам узел может раздавать WAL. max_ws=0 означает, что узел не будет источником ни для кого

pref_roles

Задаёт предпочтительный тип источника: F — Follower, L — Лидер, R — рефери, FL — сначала Follower, потом Лидер, LF — наоборот. 

Пример конфигурации для четырёхузлового кластера с каскадом: 

БД1 (Лидер):
  max_replicas=2
  priority=1000
  pref_roles=LF

БД2 (прямая реплика от Лидера):
  max_replicas=1
  priority=5000
  pref_roles=LF

БД3 (прямая реплика от Лидера):
  max_replicas=1
  priority=10000
  pref_roles=LF

БД4 (каскадная реплика от БД3):
  max_replicas=0
  can_vote=on
  can_be_leader=off
  priority=20000
  pref_roles=FL

В этой схеме БД4 не может стать лидером и не создаёт никаких walsender. Она получает данные от БД3, не нагружая ни Лидера, ни межцодовый канал.

Самовосстановление при сбоях

Одна из ключевых ценностей каскадной репликации в BiHA — это не просто построение дерева, а его автоматическое перестроение при сбоях. Разберём основные сценарии.

Сбой Лидера

Когда Лидер (БД1) падает, BiHA запускает выборы нового лидера по алгоритму Raft. Новым Лидером становится Follower с наибольшим LSN — тот, кто меньше всего отстал от старого Лидера и потеряет минимум данных. Приоритеты узлов влияют на выбор только в синхронном кластере, где все реплики гарантированно имеют одинаково актуальный WAL. Всё дерево репликации перестраивается: новый Лидер становится корнем, остальные узлы переподключаются к нему напрямую или через промежуточные узлы согласно правилу Best Follower.

Пример с конфигурацией выше (приоритет у БД2): БД2 становится Лидером → БД3 переключается на нового Лидера → БД4 продолжает получать данные от БД3. Коммит подтверждает только БД3, БД1 переходит в UNKNOWN.

Сбой промежуточного узла (ретранслятора)

Если падает БД3, узел БД4 оказывается «сиротой»: его источник исчез. BiHA обнаруживает это и запускает алгоритм Best Follower для БД4: тот ищет новый доступный источник и переподключается, в данном случае — к БД2. Коммит начинает подтверждаться только БД2, кластер продолжает работу без вмешательства администратора.

Разделение сети

При разделении сети между группами узлов поведение определяется параметрами nquorum и minnodes:

  • nquorum=3, minnodes=3: при разрыве канала между ЦОДами текущий Лидер переходит в Read-Only — запись становится невозможной до восстановления связи. Новый Лидер не избирается: ни одна из групп (БД1+БД2 и БД3+БД4) не набирает кворум. Это самый консервативный режим: данные защищены, но ценой полной недоступности записи.

  • nquorum=2, minnodes=2: группа с Лидером продолжает работу, вторая группа переходит в UNKNOWN и не становится Лидером

Это предотвращает Split-Brain даже в самых сложных сетевых сценариях.

Сценарии использования

Рассмотрим два наиболее вероятных сценария использования BiHA для решения практических задач крупных клиентов.

Сценарий 1: геораспределённый кластер (Multi-DC)

Типичная задача: основной ЦОД в Москве, резервный — в Санкт-Петербурге, DR-площадка — в Екатеринбурге. В каждом ЦОДе по 2–3 реплики для горизонтального масштабирования читающей нагрузки.

Без каскадной репликации:

Лидер в Москве отправляет WAL в Питер и Екатеринбург отдельным потоком на каждую реплику. 6 реплик — 6 walsender, межцодовые каналы работают на полную.

С каскадной репликацией:

В каждом удалённом ЦОДе назначается один узел-ретранслятор. Лидер отправляет WAL только на него, ретранслятор раздаёт данные локальным репликам. Трафик между ЦОДами сокращается кратно числу реплик на каждой площадке.

Узлы в резервных ЦОДах выставляются с can_be_leader=false — при сбое основного ЦОДа автоматического переключения не произойдёт. Администратор убеждается в готовности окружения и выполняет переключение вручную: включает can_be_leader=true на нужном узле и при необходимости задаёт biha.minnodes=1 для временной работы без остальных узлов.

Сценарий 2: разгрузка Лидера в одном ЦОДе

Каскадная репликация полезна даже без географического распределения. Если у вас 10–15 реплик для обслуживания читающей нагрузки (отчёты, аналитика, копии баз данных для 1С), Лидер вынужден поддерживать 10–15 walsender-процессов одновременно.

Каскадная схема решает это элегантно: выделяется 2–3 «промежуточных» реплики с max_ws > 0, которые принимают WAL от Лидера и раздают его остальным. Остальные реплики настраиваются с max_ws=0 и pref_roles=F — они реплицируются только от Follower, не трогая Лидера.

Лидер при этом обслуживает только 2–3 walsender вместо 15. Ресурсы, освобождённые от управления репликацией, полностью уходят на обработку транзакций.

Преимущества для бизнеса

Каскадная репликация в BiHA — это не просто техническая оптимизация. Вот что это даёт в контексте реальных Enterprise-требований:

  • Экономия на сетевых каналах. Межцодовые каналы — дорогой ресурс. Сокращение трафика репликации напрямую снижает затраты на сетевую инфраструктуру или позволяет использовать уже существующие каналы без апгрейда.

  • Масштабируемость без деградации производительности. Добавление новых реплик для читающей нагрузки больше не бьёт по Лидеру. Каждые 3–5 реплик можно выстроить в отдельную «ветку» каскада, не увеличивая нагрузку на пишущий узел.

  • Автоматическое восстановление без администратора. Если промежуточный узел-ретранслятор падает, BiHA сам перестраивает дерево. «Осиротевшие» реплики находят новый источник и продолжают работу.

  • Контролируемое переключение между ЦОДами. Параметр can_be_leader=false позволяет держать резервный ЦОД в режиме горячего standby, не опасаясь автоматического «угона» лидера. Переключение происходит только по команде администратора, когда он убедился, что все сервисы готовы к переходу.

  • Замена Patroni без дополнительных зависимостей. BiHA — встроенный компонент Postgres Pro Enterprise, сертифицированного по требованиям ФСТЭК. Не нужно поддерживать отдельный стек: etcd или Consul для хранения состояния, отдельные процессы Patroni на каждом узле, скрипты интеграции с балансировщиками. Всё в одном продукте.