← Назад к вопросам

Для чего используется Patroni в PostgreSQL?

3.0 Senior🔥 121 комментариев
#DevOps и инфраструктура#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI28 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Для чего используется Patroni в PostgreSQL

Определение

Patroni — это инструмент для управления высокой доступностью (HA) кластера PostgreSQL. Он автоматически переводит резервный сервер в основной при сбое основного, без участия администратора.

Главная идея: если основной PostgreSQL упал, Patroni автоматически поднимет резервный сервер вместо него.

Проблема без Patroni

Сценарий: основной PostgreSQL упал

Производство:
┌────────────────┐
│ PostgreSQL OK  │
│ (primary)      │
└────────────────┘
       ↓
    СБОЙ! 💥
       ↓
┌────────────────┐
│ PostgreSQL ❌  │  Основной сервер упал!
│ (primary)      │
└────────────────┘

┌────────────────┐
│ PostgreSQL OK  │  Резервный сервер работает,
│ (standby)      │  но НЕ может писать!
└────────────────┘

❌ Приложение не может писать в БД
❌ Пользователи видят ошибки
❌ Нужен администратор для переключения
❌ RTO (Recovery Time Objective): 10+ минут

Решение без Patroni требует ручных шагов:

# 1. Администратор замечает, что primary упал (5 минут)
# 2. SSH на standby сервер
ssh admin@standby

# 3. Повысить standby до primary
pg_ctl promote -D /var/lib/postgresql/data

# 4. Обновить строку подключения в приложении
# 5. Перезагрузить приложение
# 6. Проверить, что всё работает

# Итого: 15-30 минут простоя

С Patroni (автоматическое переключение)

Производство с Patroni:
┌────────────────┐
│ PostgreSQL OK  │
│ (primary)      │  Patroni следит за здоровьем
│ + Patroni ✅   │
└────────────────┘
       ↓
    СБОЙ! 💥
       ↓
┌────────────────┐
│ PostgreSQL ❌  │  Primary упал
│ (primary)      │
└────────────────┘

┌────────────────┐
│ PostgreSQL OK  │  Patroni АВТОМАТИЧЕСКИ
│ (standby→primary)│ повысил standby за 1-3 секунды
│ + Patroni ✅   │
└────────────────┘

✅ Приложение переключилось на новый primary
✅ Нет простоя для пользователей
✅ RTO (Recovery Time Objective): 1-3 секунды

Архитектура Patroni

┌─────────────────────────────────────────────────────┐
│         Distributed Consensus Store (ETCD/Consul)   │
│  Хранит информацию о ком сейчас primary             │
└─────────────────────────────────────────────────────┘
         ↑                           ↑
         │                           │
┌────────┴─────────┐       ┌────────┴─────────┐
│  Patroni Node 1  │       │  Patroni Node 2  │
│  (Primary)       │       │  (Standby)       │
│  ┌────────────┐  │       │  ┌────────────┐  │
│  │ PostgreSQL │  │       │  │ PostgreSQL │  │
│  └────────────┘  │       │  └────────────┘  │
│  Heartbeat: OK   │       │  Heartbeat: OK   │
└──────────────────┘       └──────────────────┘

Если Primary упал → Patroni на Standby видит это → Повышает себя

Компоненты Patroni

1. Patroni Daemon — процесс на каждом PostgreSQL сервере:

# Установка Patroni
pip install patroni[etcd]

# Запуск Patroni
patroni /etc/patroni/postgresql.yml

2. ETCD (или Consul) — хранилище состояния кластера:

# ETCD хранит:
etcdctl get /patroni/primary
# → "db-primary-01"  (какой сервер сейчас primary)

etcdctl get /patroni/db-primary-01/conn_address
# → "10.0.0.10:5432"

3. VIP (Virtual IP) или DNS — фиксированный адрес для подключения:

// Приложение подключается к одному адресу
const client = new Pool({
  host: 'db.production.internal', // Patroni управляет этим адресом
  port: 5432
});

// Patroni автоматически обновляет DNS при переключении
// Приложение даже не заметит переключения (reconnect за секунды)

Конфиг Patroni (postgresql.yml)

scope: my-postgres-cluster  # Имя кластера

namespace: /patroni

etcd:
  hosts:
    - 10.0.0.20:2379  # ETCD сервер
    - 10.0.0.21:2379
    - 10.0.0.22:2379

postgresql:
  data_dir: /var/lib/postgresql/data
  pgpass: /var/lib/postgresql/.pgpass
  listen: 0.0.0.0:5432
  connect_address: 10.0.0.10:5432  # IP этого сервера
  
  authentication:
    username: patroni
    password: patroni_password
  
  parameters:  # PostgreSQL конфиг
    max_connections: 200
    shared_buffers: 256MB
    effective_cache_size: 1GB

rest_api:
  listen: 0.0.0.0:8008
  connect_address: 10.0.0.10:8008

ttl: 30  # Время жизни лидера (primary) в секундах
loop_wait: 10  # Интервал проверки здоровья
maximum_lag_on_failover: 1048576  # Max LAG перед failover

initdb:
  - encoding: UTF8
  - locale: en_US.UTF-8

Как работает автоматическое переключение

Сценарий: Primary упал

До сбоя:
┌──────────────────────┐
│ Primary (Node 1)     │
│ - Пишет в ETCD       │
│ - Heartbeat: OK      │
└──────────────────────┘

Primary запишет в ETCD каждые 10 секунд:
etcd key: /patroni/my-cluster/leader → Node-1
TTL: 30 секунд

┌──────────────────────┐
│ Standby (Node 2)     │
│ - Слушает ETCD       │
│ - Heartbeat: OK      │
└──────────────────────┘

Шаг 1: Primary упал
┌──────────────────────┐
│ Primary (Node 1) ❌  │  Не может писать в ETCD
└──────────────────────┘

Шаг 2: TTL истёк (30 секунд)
ETCD забывает, кто primary:
key /patroni/my-cluster/leader → (ПУСТО)

Шаг 3: Standby видит, что primary исчезнул
┌──────────────────────┐
│ Standby (Node 2)     │
│ "Primary пропал!"    │
│ Я становлюсь primary!│
└──────────────────────┘

Шаг 4: Standby написал в ETCD
etcd key: /patroni/my-cluster/leader → Node-2

Шаг 5: Приложение переключилось
DNS: db.production → 10.0.0.11 (новый primary)

✅ Переключение произошло за 30-35 секунд

Примеры использования в production

Пример 1: 3-нодный кластер PostgreSQL

Производство:
┌──────────────┐
 Node 1         Primary
 PostgreSQL     (принимает запросы на запись)
 Patroni      
└──────────────┘

┌──────────────┐
 Node 2         Standby
 PostgreSQL     (реплицирует данные)
 Patroni      
└──────────────┘

┌──────────────┐
 Node 3         Standby
 PostgreSQL     (реплицирует данные)
 Patroni      
└──────────────┘

ETCD кластер для хранения состояния

Пример 2: Node.js приложение с Patroni

const { Pool } = require('pg');

const pool = new Pool({
  // Вместо IP адреса, используем DNS имя
  // Patroni управляет этим DNS
  host: 'postgres.db.svc.cluster.local',
  port: 5432,
  database: 'myapp',
  user: 'app_user',
  password: process.env.DB_PASSWORD,
  
  // Автоматический reconnect при переключении
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
});

app.post('/users', async (req, res) => {
  const client = await pool.connect();
  try {
    await client.query('INSERT INTO users (name) VALUES ($1)', [req.body.name]);
    res.json({ status: 'ok' });
  } catch (error) {
    // При переключении Primary → Standby
    // соединение разорвётся, но pool автоматически переподключится
    res.status(500).json({ error: error.message });
  } finally {
    client.release();
  }
});

Преимущества Patroni

Автоматическое переключение — без участия администратора ✅ Высокая доступность — RTO < 1 минута ✅ Масштабируемость — работает с кластерами из 3+ узлов ✅ Безопасность — не теряются данные (sync replication опция) ✅ Мониторинг — REST API для проверки статуса ✅ Простота — YAML конфиг, не нужно писать скрипты

Когда использовать Patroni

Используй Patroni когда:

  • Production окружение с требованием HA
  • Нужна автоматическая отказоустойчивость
  • Есть несколько PostgreSQL серверов
  • Допустим простой в несколько секунд
  • Используешь Kubernetes (есть встроенная поддержка)

Не нужен Patroni:

  • Разработка локально
  • Простой проект на одном сервере
  • AWS RDS PostgreSQL (управляется AWS)
  • Небольшие нагрузки

Альтернативы

  • AWS RDS — облачное управление HA (самое простое)
  • PostgreSQL built-in replication — простая репликация без failover
  • Stolon — похож на Patroni, тоже для HA
  • pg_auto_failover — от PostgreSQL разработчиков

Выводы

Patroni — это критичный инструмент для production кластеров PostgreSQL, который:

  • Обеспечивает автоматическую отказоустойчивость
  • Убирает простои при сбое основного сервера
  • Упрощает операции (не нужен ручной failover)
  • Масштабируется на большие кластеры

В production окружении, где нельзя терять данные и допустимый простой минимален, Patroni — это стандартное решение.