Skip to content

Группа central на нескольких серверах

Резервирование объясняет, из чего состоит инсталляция с резервом и что меняет второй инстанс. Эта страница — про то, как её собрать: какие настройки задать каждой машине, что написать стримерам и что проверить, когда всё поднялось.

Здесь описан парк из независимых серверов — по машине на инстанс. Попробовать то же самое на одном ноутбуке, не арендуя серверов, можно по практикуму в Docker: там та же группа собирается из контейнеров за несколько минут.

Что именно разворачивается

Инсталляция с резервом состоит из четырёх частей, и только одна из них — сама Catena:

  • Один кластер PostgreSQL, доступный всем инстансам по одному адресу. Это единственное хранилище состояния и единственная часть, отказоустойчивость которой Catena на себя не берёт.
  • Два и более инстанса central — отдельные машины с одинаковым конфигом, отличающиеся ролями и объявленным адресом.
  • Стримеры — отдельные машины, которым задан не адрес одного инстанса, а список адресов группы.
  • Точка входа оператора — один адрес, за которым живой инстанс: DNS-имя с переключением или балансировщик.

Правило, с которого начинается такая инсталляция: central и вещание живут на разных машинах. Локальный стример внутри процесса central здесь не годится — он разделяет судьбу процесса, и его стримы падают вместе с управлением.

Сколько чего нужно

Часть Сколько Замечание
PostgreSQL Один логический кластер Два независимых сервера базы — это две разные инсталляции, а не резерв
Инстансы central Два и больше Третий добавляется тем же конфигом; переписывать существующие не нужно
Стримеры Сколько требует эфир Резервируются не здесь, а размещением
Точка входа оператора Один адрес Стримеры через него не ходят

Конфиг инстанса central

Инстансы группы отличаются друг от друга ровно двумя строками — объявленным адресом и набором ролей. Всё остальное у них одинаково, включая строку подключения к базе.

Первый инстанс:

listeners:
  http:
    - port: 80

central:
  database_url: postgres://central:пароль@db.example.com:5432/central
  admin_keys:
    - ключ-управления
  roles: [run, migrate, layouter, stats]
  advertise_url: http://central-a.example.com

api_auth:
  login: admin
  password: пароль-оператора

Второй — то же самое без роли migrate и со своим адресом:

central:
  database_url: postgres://central:пароль@db.example.com:5432/central
  admin_keys:
    - ключ-управления
  roles: [run, layouter, stats]
  advertise_url: http://central-b.example.com

Роли — это притязания, а не назначения

Роль в конфиге означает «эта машина готова делать такую работу», а не «эта машина её делает». Кто из инстансов действительно исполняет работу, решает PostgreSQL, а не конфиг, — поэтому layouter и stats заявлены у обоих, и это не ошибка и не двойной запуск.

  • run — обслуживать запросы: консоль, management API, приём синхронизации со стримеров, выдачу метрик. Нужна каждому инстансу.
  • migrate — накатить миграции схемы при старте.
  • layouter — исполнять прогоны размещения.
  • stats — держать картину «прямо сейчас» по всему кластеру.

Единственная роль, которую нельзя оставлять у всех, — migrate. Она не защищена мандатом: два процесса, стартовавшие одновременно, погонят миграции наперегонки. Поэтому схему накатывает один инстанс, а остальные стартуют после него.

Это же — причина не оставлять roles пустым на втором инстансе: пустой список означает не «никаких ролей», а все четыре, включая migrate.

Объявленный адрес

advertise_url — адрес, по которому до этой машины достучатся соседи по группе. Он нужен потому, что картину «прямо сейчас» держит один инстанс, а остальные ходят к ней по сети: держатель записывает свой адрес, соседи читают его оттуда.

Адрес балансировщика здесь не годится — он привёл бы соседа к самому себе. Адрес обязан быть адресом конкретной машины.

Настройку можно и не задавать: инстанс без объявленного адреса полноценно работает и даже может держать картину — но соседи до неё не дойдут и скажут об этом в лог. В консоли такая строка помечена отдельно, см. проверку после развёртывания.

Лицензия

Лицензия нужна каждому процессу central, а не одному на группу: без неё процесс не стартует вовсе. Ключ и объявленный продукт у инстансов одинаковые.

Кто что исполняет: мандаты

Работу, дубль которой вреден, в группе исполняет один инстанс — тот, который взял на неё мандат. Мандат живёт в PostgreSQL и выдаётся на отдельном соединении, поэтому гибель процесса освобождает его сама, без разбора зависших исполнителей по таймаутам: сессия умерла — мандат свободен.

Мандатов несколько, и они независимы. Единого лидера у central нет: layouter и stats могут оказаться на разных машинах, и это штатное состояние, а не перекос.

У каждой выдачи есть номер — эпоха. Она растёт при смене держателя и едет вместе с каждой записью: инстанс, очнувшийся после паузы уже не держателем, получает отказ на записи, а не портит размещение задним числом. Поэтому переход мандата безопасен и не требует ручного подтверждения.

Смена держателя занимает секунды — столько, сколько нужно PostgreSQL, чтобы заметить смерть сессии, а соседу — чтобы прийти за освободившимся мандатом.

Инстанс, не держащий ничего, — не запасной и не спящий: он полноценно обслуживает консоль, API и синхронизацию стримеров. Мандат касается только фоновой работы.

Конфиг стримера

Стример обращается к группе, а не к процессу, поэтому в его конфиге список адресов:

managed_by:
  name: streamer-01
  url:
    - http://central-a.example.com
    - http://central-b.example.com
  join_token: токен-присоединения

Порядок в списке — это стартовое предпочтение, а не постоянная привязка. Стример держится текущего адреса, пока тот отвечает, и переходит к следующему после неудавшегося запроса. Обратно он сам не возвращается: пока новый адрес отвечает, менять его незачем, а перебор ради равномерности только размазал бы машину по группе.

Второй адрес обязателен, а не желателен. Разрыв петли синхронизации — единственный признак живости стримера, который есть у central. Стример, оставшийся без единственного адреса, через полторы минуты числится offline, после чего лейаутер честно уводит его стримы на другую машину — с живой и вещающей. Смерть одного инстанса управления превращается в переезд половины эфира.

Список удобно поделить по половинам парка: одной половине первым адресом задать первый инстанс, другой — второй. Тогда в спокойном состоянии нагрузка приёма синхронизации распределена, а при гибели любого инстанса на второй адрес уходит только его половина.

Точка входа оператора

Оператору нужен один адрес, который сам находит живой инстанс: DNS-имя с переключением или балансировщик перед группой. Состояния у обработчика запросов своего нет, поэтому на запрос оператора отвечает любой инстанс.

Стримеры через эту точку ходить не должны: у них свой список адресов, а лишний посредник на пути синхронизации только добавит точку отказа.

Порядок развёртывания

  1. Поднять PostgreSQL и создать базу.
  2. Запустить первый инстанс — тот, у которого есть роль migrate. Дождаться, пока он ответит на запросы: схема накатывается до готовности.
  3. Запустить остальные инстансы.
  4. Открыть окно присоединения и завести стримеры, задав каждому список адресов группы.
  5. Направить точку входа оператора на группу.

Пакет на машинах инстансов — catena-base, тот же, что и на стримерах: на вопрос установки о существующем PostgreSQL называется адрес общей базы, а роли и объявленный адрес задаются конфигом выше. Пакет catena здесь не нужен — он заводит базу на своей же машине, а группе она нужна отдельно от инстансов.

Порядок важен только на первом шаге: остальные инстансы не поднимутся раньше схемы, а стримеры не присоединятся раньше живого central.

Что проверить после развёртывания

Всё, что нужно посмотреть, лежит в консоли в разделе Кластер → Central.

  • В таблице столько строк, сколько инстансов. Строка появляется через секунды после старта. Не появилась — инстанс не дошёл до базы.
  • У каждой строки заполнен «Объявленный адрес». Пометка «не объявлен» означает, что соседи до этого инстанса не дойдут: ему не задан advertise_url.
  • Столбец «Притязания» показывает заявленные роли. Убедитесь, что migrate заявлен ровно у одного.
  • Столбец «Держит мандаты» непустой хотя бы у одного инстанса. Пусто у всех — значит, ни один не заявил ролей layouter и stats, и ни размещения, ни картины «прямо сейчас» в группе нет.
  • Столбец «Сборка» одинаков у всех строк. Разные версии в группе — штатное состояние только на время обновления.
  • Раздел «Стримеры» показывает весь парк с любого инстанса. Половина парка, видимая с одного адреса, и другая половина — с другого, означают, что инстансы не видят картину друг друга: проверьте advertise_url.

Проверять переключение руками не нужно и не стоит на работающей инсталляции — для этого есть практикум на одноразовом стенде.

Чего эта схема не делает

  • Не резервирует базу. Отказоустойчивость PostgreSQL — задача самой базы: реплика с переключением или управляемый инстанс провайдера.
  • Не заменяет бэкап. Резерв защищает от потери машины, но не от ошибочного удаления — см. Бэкап и восстановление.
  • Не касается эфира. Стримы вещают и пишут архив без central; резервируется только управление, см. Автономия стримера.