Ответ
Настраивал и поддерживал высокодоступные кластеры PostgreSQL с Patroni в production-среде в течение 3 лет. Основной стек: Patroni + etcd + PgBouncer + monitoring.
Архитектура типичного кластера:
┌─────────────────────────────────────────────────┐
│ Load Balancer (HAProxy) │
│ read-write read-only │
└───────────────┬──────────────────┬──────────────┘
│ │
┌───────▼──────┐ ┌───────▼──────┐
│ Patroni 1 │ │ Patroni 2 │
│ (Leader) │ │ (Replica) │
│ PostgreSQL │ │ PostgreSQL │
└───────┬──────┘ └───────┬──────┘
│ │
┌───────▼──────────────────▼──────┐
│ etcd Cluster (3 nodes) │
│ для распределенного консенсуса│
└──────────────────────────────────┘
Конфигурация Patroni (/etc/patroni/patroni.yml):
scope: postgres-prod
namespace: /service/
name: pg-node-1
restapi:
listen: 0.0.0.0:8008
connect_address: 10.0.1.10:8008
authentication:
username: "{{ patroni_api_user }}"
password: "{{ patroni_api_password }}"
etcd:
hosts:
- etcd1:2379
- etcd2:2379
- etcd3:2379
protocol: http
retry_timeout: 10
ttl: 30
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 100
shared_buffers: 128MB
wal_level: logical
hot_standby: "on"
archive_mode: "on"
archive_command: 'cp %p /var/lib/postgresql/wal/%f'
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.1.10:5432
data_dir: /var/lib/postgresql/14/main
bin_dir: /usr/lib/postgresql/14/bin
pgpass: /var/lib/postgresql/.pgpass
authentication:
replication:
username: replicator
password: "{{ replication_password }}"
superuser:
username: postgres
password: "{{ postgres_password }}"
watchdog:
mode: required
device: /dev/watchdog
safety_margin: 5
Решаемые задачи:
- Автоматический failover — при падении лидера Patroni выбирает новую ноду за 30-60 секунд
- Репликация — настройка синхронной/асинхронной репликации с контролем лага
- Switchover — плановое переключение без простоя:
patronictl switchover postgres-prod --master pg-node-1 --candidate pg-node-2 - Мониторинг — экспорт метрик в Prometheus (endpoint
/metrics), алерты на:- Смену лидера
- Лаг репликации > threshold
- Нет кворума в etcd
- Интеграция с PgBouncer — автоматическое обновление
pgbouncer.iniпри смене лидера
Проблемы и решения:
- Split-brain — предотвращаем через watchdog и правильные таймауты
- Network partitions — настройка
ttlиretry_timeoutсогласно сетевой задержке - Большие WAL файлы — использование
pg_rewindвместо полного перебилда реплик
Ответ 18+ 🔞
Да ты представь, три года, Карл, три года я с этой штукой жил! Patroni, ёпта, как будто жена вторая, только без скандалов, но с вечными приколами. Ну, то есть, скандалы тоже были, но их я сам и провоцировал, когда что-то накосячил.
В общем, сидишь такой, пьешь кофе, а в мониторе — овердохуища алертов. И думаешь: «Э, сабака сука, опять что?». А это просто реплика отстала на пару мегабайт, потому что кто-то отчет за месяц выгружает. Но в целом, если настроить всё не как попало, а с мозгами, то штука живучая, как таракан после ядерной зимы.
Вот смотри, как обычно это безобразие выглядит. Картинка для наглядности, чтобы понимать, кто кому и куда:
┌─────────────────────────────────────────────────┐
│ Load Balancer (HAProxy) │
│ read-write read-only │
└───────────────┬──────────────────┬──────────────┘
│ │
┌───────▼──────┐ ┌───────▼──────┐
│ Patroni 1 │ │ Patroni 2 │
│ (Leader) │ │ (Replica) │
│ PostgreSQL │ │ PostgreSQL │
└───────┬──────┘ └───────┬──────┘
│ │
┌───────▼──────────────────▼──────┐
│ etcd Cluster (3 nodes) │
│ для распределенного консенсуса│
└──────────────────────────────────┘
А теперь самое вкусное — конфиг. Это святая святых, его надо вылизать до блеска. Вот примерно как он выглядит, только пароли, ясное дело, спрятаны, а то мало ли.
scope: postgres-prod
namespace: /service/
name: pg-node-1
restapi:
listen: 0.0.0.0:8008
connect_address: 10.0.1.10:8008
authentication:
username: "{{ patroni_api_user }}"
password: "{{ patroni_api_password }}"
etcd:
hosts:
- etcd1:2379
- etcd2:2379
- etcd3:2379
protocol: http
retry_timeout: 10
ttl: 30
bootstrap:
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
max_connections: 100
shared_buffers: 128MB
wal_level: logical
hot_standby: "on"
archive_mode: "on"
archive_command: 'cp %p /var/lib/postgresql/wal/%f'
postgresql:
listen: 0.0.0.0:5432
connect_address: 10.0.1.10:5432
data_dir: /var/lib/postgresql/14/main
bin_dir: /usr/lib/postgresql/14/bin
pgpass: /var/lib/postgresql/.pgpass
authentication:
replication:
username: replicator
password: "{{ replication_password }}"
superuser:
username: postgres
password: "{{ postgres_password }}"
watchdog:
mode: required
device: /dev/watchdog
safety_margin: 5
И вот за этим всем следишь, как за маленьким, но очень вредным ребёнком. Что мы этим безобразием решаем? Да много чего!
- Автоматический фейловер. Это когда лидер, грубо говоря, накрылся медным тазом. Раньше все бегали с криками «ААА! БД упала!», а теперь Patroni сам, за 30-60 секунд, выбирает нового предводителя. Главное — чтобы etcd был в сознании, а то будет пиздопроебибна полная.
- Репликация. Настраиваешь, как данные бегать должны. Можно синхронно — надёжно, но медленнее. Можно асинхронно — быстрее, но есть риск немного отстать. Лаг контролируешь, чтобы реплика не превратилась в музей устаревших данных.
- Плановый свичовер. Это для красоты. Хочешь на другой сервер переехать без простоев — пожалуйста, одна команда:
patronictl switchover postgres-prod --master pg-node-1 --candidate pg-node-2И все приложения даже не чихнут, если, конечно, PgBouncer правильно настроен. А если нет — ну, сам от себя охуеешь, когда начнутся звонки.
- Мониторинг. Без него — никуда. Patroni метрики наружу отдаёт, ты их в Prometheus пихаешь и ставишь алерты на всё: смена лидера, лаг большой, etcd кворум потерял. Доверия ебать ноль ко всему живому, только метрики.
- PgBouncer. Чтобы приложения не тупили, когда лидер сменился, надо, чтобы пулер соединений это узнал. Приходится скрипты городить, которые конфиг PgBouncer'а автоматом обновят. Волнение ебать, пока это не заработает как часы.
А теперь про грабли, на которые я сам не раз наступал. Их, блядь, как собак нерезаных.
- Split-brain (раздвоение личности). Это самый страшный сон. Когда две ноды решают, что они обе — лидеры, и начинают писать в базу кто во что горазд. Итог — пиздец полный и потеря данных. От этого спасает watchdog (железный или софтовый) и правильно подобранные таймауты. Если сеть лагает, а
ttlмаленький — жди беды. - Проблемы с сетью. Сеть — она такая хитрая жопа. Может заглючить, и ноды перестанут друг друга видеть. Надо
retry_timeoutиttlвыставлять с умом, с запасом, чтобы из-за мелкой икоты кластер не начал сам с собой войну. - Большие WAL файлы и сломанные реплики. Раньше, если реплика отстала сильно или сломалась, её надо было с нуля пересоздавать — долго и грустно. Теперь есть
pg_rewind— магия, которая позволяет отмотать изменения и подцепиться обратно, как ни в чём не бывало. Просто надо в конфигеuse_pg_rewind: trueне забыть поставить.
В общем, история такая: настроил один раз и забыл? Хуй там! Это как живой организм, за ним глаз да глаз нужен. Но когда всё летает — красота, можно и кофе спокойно допить.