====== Настройка отказоустойчивого кластера PostgreSQL в Linux ======
Отказоустойчивость PostgreSQL обеспечивается переключением ролей сервера с Реплики на Мастер СУБД и механизмом потоковой репликации, позволяющим передавать изменения с ведущего сервера на ведомые так, чтобы в каждый момент времени на ведомом сервере хранилась полная и консистентная копия базы данных.Для настройки отказоустойчивости PostgreSQL будет использоваться следующее ПО: * OS: Deiban 11 или 12 * Patroni * Etcd * Keepalived * Pgbouncer * Haproxy Тестовый стенд развернут на системе виртуализации VirtualBox, ip-адрессация дефолтная Кластер будет построен на 3-х нодах. Будет рассмотрена конфигурация 1 master и 1 replica сервер СУДБ PostgreSQL. Но эту конфигурацию без труда можно переделать в 1 master и 2 replicas Таким образом, ПО на хостах будет следующим:
db1-1: etcd, keepalived, PostgreSQL, Partoni, PGbouncer, HAproxy
db1-2: etcd, keepalived, PostgreSQL, Partoni, PGbouncer, HAproxy
db1-3: etcd
==== Подготовка хостов ====
Обновим ОС и установим (по желанию) базовый набор ПО
$ sudo apt update && sudo apt upgrade -y
$ sudo apt -y install nano curl bind9-utils dnsutils telnet wget net-tools traceroute git tcpdump rsync open-vm-tools mlocate htop tar zip unzip cloud-guest-utils gdisk
$ sudo apt autoremove -y
На всех 3-х нодах приводим файл hosts к виду:
$ sudo nano /etc/hosts
10.0.2.15 db1-1
10.0.2.16 db1-2
10.0.2.17 db1-3
Переименуем каждую ноду через hostnamectl
$ sudo hostnamectl set-hostname db1-1 # для каждой ноды свой hostname
==== Установка Etcd (All nodes) ====
Скачиваем дистрибутив и распаковываем. На момент подготовки стенда, финальная версия etcd была: 3.5.5
$ cd /tmp
$ wget https://github.com/etcd-io/etcd/releases/download/v3.5.5/etcd-v3.5.5-linux-amd64.tar.gz
$ tar xzvf etcd-v3.5.5-linux-amd64.tar.gz
Перемещаем бинарники в каталог /usr/local/bin
$ sudo mv /tmp/etcd-v3.5.5-linux-amd64/etcd* /usr/local/bin/
Проверяем
$ etcd --version
etcd Version: 3.5.5
Git SHA: 19002cfc6
Go Version: go1.16.15
Go OS/Arch: linux/amd64
$ etcdctl version
etcdctl version: 3.5.5
API version: 3.5
$ etcdutl version
etcdutl version: 3.5.5
API version: 3.5
==== Предварительная настройка etcd (All nodes) ====
Создаем системную группу и пользователя
$ sudo groupadd --system etcd
$ sudo useradd -s /sbin/nologin --system -g etcd etcd
Создаем директории, назначаем владельца, права доступа
$ sudo mkdir /opt/etcd
$ sudo mkdir /etc/etcd
$ sudo chown -R etcd:etcd /opt/etcd
$ sudo chmod -R 700 /opt/etcd/
Создаем конфиги для etcd (для каждой ноды разный)
db1-1:
$ sudo nano /etc/etcd/etcd.conf
ETCD_NAME="etcd1"
ETCD_LISTEN_CLIENT_URLS="http://10.0.2.15:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.2.15:2379"
ETCD_LISTEN_PEER_URLS="http://10.0.2.15:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.2.15:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_INITIAL_CLUSTER="etcd1=http://10.0.2.15:2380,etcd2=http://10.0.2.16:2380,etcd3=http://10.0.2.17:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="10000"
ETCD_HEARTBEAT_INTERVAL="2000"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"
ETCD_ENABLE_V2="true"
db1-2
$ sudo nano /etc/etcd/etcd.conf
ETCD_NAME="etcd2"
ETCD_LISTEN_CLIENT_URLS="http://10.0.2.16:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.2.16:2379"
ETCD_LISTEN_PEER_URLS="http://10.0.2.16:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.2.16:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_INITIAL_CLUSTER="etcd1=http://10.0.2.15:2380,etcd2=http://10.0.2.16:2380,etcd3=http://10.0.2.17:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="10000"
ETCD_HEARTBEAT_INTERVAL="2000"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"
ETCD_ENABLE_V2="true"
db1-3
$ sudo nano /etc/etcd/etcd.conf
ETCD_NAME="etcd3"
ETCD_LISTEN_CLIENT_URLS="http://10.0.2.17:2379,http://127.0.0.1:2379"
ETCD_ADVERTISE_CLIENT_URLS="http://10.0.2.17:2379"
ETCD_LISTEN_PEER_URLS="http://10.0.2.17:2380"
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://10.0.2.17:2380"
ETCD_INITIAL_CLUSTER_TOKEN="etcd-postgres-cluster"
ETCD_INITIAL_CLUSTER="etcd1=http://10.0.2.15:2380,etcd2=http://10.0.2.16:2380,etcd3=http://10.0.2.17:2380"
ETCD_INITIAL_CLUSTER_STATE="new"
ETCD_DATA_DIR="/var/lib/etcd"
ETCD_ELECTION_TIMEOUT="10000"
ETCD_HEARTBEAT_INTERVAL="2000"
ETCD_INITIAL_ELECTION_TICK_ADVANCE="false"
ETCD_ENABLE_V2="true"
Создаем Systemd Unit на каждой из нод
$ sudo nano /etc/systemd/system/etcd.service
[Unit]
Description=Etcd Server
Documentation=https://github.com/etcd-io/etcd
After=network.target
After=network-online.target
Wants=network-online.target
[Service]
User=etcd
Type=notify
#WorkingDirectory=/var/lib/etcd/
WorkingDirectory=/opt/etcd/
EnvironmentFile=-/etc/etcd/etcd.conf
User=etcd
# set GOMAXPROCS to number of processors
ExecStart=/bin/bash -c "GOMAXPROCS=$(nproc) /usr/local/bin/etcd
Restart=on-failure
LimitNOFILE=65536
IOSchedulingClass=realtime
IOSchedulingPriority=0
Nice=-20
[Install]
WantedBy=multi-user.target
Добавляем сервис в автозагрузку и запускаем
$ sudo systemctl daemon-reload
$ sudo systemctl enable etcd
$ sudo systemctl start etcd
==== Управление Etcd ====
Смотрим ноды кластера
$ ETCDCTL_API=2 etcdctl member list
Проверяем кто лидер
$ etcdctl endpoint status --cluster -w table
Здоровье кластера
$ etcdctl endpoint health --cluster -w table
еще команды:
$ ETCDCTL_API=2 etcdctl member list
$ ETCDCTL_API=3 etcdctl -w table --endpoints=db1-1:2379,db1-2:2379,db1-3:2379 endpoint status
$ ETCDCTL_API=3 etcdctl endpoint status --cluster -w table
$ etcdctl endpoint status --cluster
$ etcdctl endpoint health --cluster
==== Установка Postgresql 15 из репозитория (db1-1, db1-2) ====
Добавляем репозиторий и устанавливаем PostgreSQL
$ sudo apt -y install gnupg2
$ sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main"> /etc/apt/sources.list.d/pgdg.list'
$ wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
$ sudo apt update
$ sudo apt -y install postgresql-15
$ sudo ln -s /usr/lib/postgresql/15/bin/* /usr/sbin/
Добавляем пользователя replicator
$ sudo -u postgres psql
=# create user replicator replication login encrypted password 'passwd';
Задаем пароль для пользователя postgres
=# \password postgres;
Enter new password for user "postgres": passwd
Enter it again: passwd
Подключаем расширения
=# CREATE EXTENSION pg_stat_statements;
=# LOAD 'auto_explain';
Создаем пользователя pgbouncer
=# create user pgbouncer password '39xYw2KcwV';
=# \q
Редактируем pg_hba.conf
$ sudo nano /etc/postgresql/15/main/pg_hba.conf
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
host all all 10.0.2.0/24 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication replicator localhost trust
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
host replication replicator 10.0.2.0/24 md5
На второй и ноде удаляем (от пользователей root или postgres) содержимое каталога /var/lib/postgresql/15/main, т.к. этот каталог среплицируется после запуска Patroni
$ sudo su
# rm -rf /var/lib/postgresql/15/main/*
# exit
==== Установка KeepAlived (db1-1, db1-2) ====
Установим ПО
$ sudo apt -y install keepalived
Правим конфиг
db1-1:
$ sudo nano /etc/keepalived/keepalived.conf
global_defs {
router_id ocp_vrrp
enable_script_security
script_user root
}
vrrp_script haproxy_check {
script "/usr/libexec/keepalived/haproxy_check.sh"
interval 5 # check every 5 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_1 {
interface enp0s3
virtual_router_id 11
priority 101 # 101 on master, 100 on backup
advert_int 10
state MASTER
virtual_ipaddress {
10.0.2.11
}
track_script {
haproxy_check
}
authentication {
auth_type PASS
auth_pass ehr0wg1chww8
}
}
db1-2:
$ sudo nano /etc/keepalived/keepalived.conf
global_defs {
router_id ocp_vrrp
enable_script_security
script_user root
}
vrrp_script haproxy_check {
script "/usr/libexec/keepalived/haproxy_check.sh"
interval 5 # check every 5 seconds
weight 2 # add 2 points of prio if OK
}
vrrp_instance VI_1 {
interface enp0s3
virtual_router_id 11
priority 100 # 101 on master, 100 on backup
advert_int 10
state BACKUP
virtual_ipaddress {
10.0.2.11
}
track_script {
haproxy_check
}
authentication {
auth_type PASS
auth_pass ehr0wg1chww8
}
}
В данном конфиге ip 10.0.2.11 – кластерный плавающий ip
Создаем каталог и скрипт проверки HAproxy (до установки и настройки HAproxy не будет отрабатывать)
$ sudo mkdir -p /usr/libexec/keepalived/
$ sudo nano /usr/libexec/keepalived/haproxy_check.sh
#!/bin/bash
/bin/kill -0 `cat /var/run/haproxy/haproxy.pid`
Назначаем права
$ sudo chmod 700 /usr/libexec/keepalived/haproxy_check.sh
$ sudo chmod +x /usr/libexec/keepalived/haproxy_check.sh
Запускаем сервис, добавляем в автозагрузку, проверяем
$ sudo systemctl start keepalived
$ sudo systemctl enable keepalived
$ sudo systemctl status keepalived
==== Установка Patroni (db1-1, db1-2) ====
Устанавливаем ПО
$ sudo apt -y install python3 python3-pip python3-dev python3-psycopg2 libpq-dev
$ sudo pip3 install --upgrade pip
$ sudo pip3 install psycopg2
$ sudo pip3 install psycopg2-binary
$ sudo pip3 install wheel
$ sudo pip3 install patroni
$ sudo pip3 install python-etcd
Создаем каталог /etc/patroni/
$ sudo mkdir /etc/patroni/
Создаем конфиг patroni.yml
$ sudo nano /etc/patroni/patroni.yml
---
scope: postgres-cluster # одинаковое значение на всех узлах
name: db1-1 # разное значение на всех узлах
namespace: /service/ # одинаковое значение на всех узлах
restapi:
listen: 10.0.2.15:8008 # разное значение на всех узлах
connect_address: 10.0.2.15:8008 # разное значение на всех узлах
authentication:
username: patroni
password: 'passwd'
etcd:
hosts: 10.0.2.15:2379,10.0.2.16:2379,10.0.2.17:2379 # список всех узлов, на которых установлен etcd
bootstrap:
method: initdb
dcs:
ttl: 60
loop_wait: 10
retry_timeout: 27
maximum_lag_on_failover: 2048576
master_start_timeout: 300
synchronous_mode: true
synchronous_mode_strict: false
synchronous_node_count: 1
# standby_cluster:
# host: 127.0.0.1
# port: 1111
# primary_slot_name: patroni
postgresql:
use_pg_rewind: false
use_slots: true
parameters:
max_connections: 800
superuser_reserved_connections: 5
max_locks_per_transaction: 64
max_prepared_transactions: 0
huge_pages: try
shared_buffers: 512MB
work_mem: 128MB
maintenance_work_mem: 256MB
effective_cache_size: 4GB
checkpoint_timeout: 15min
checkpoint_completion_target: 0.9
min_wal_size: 2GB
max_wal_size: 4GB
wal_buffers: 32MB
default_statistics_target: 1000
seq_page_cost: 1
random_page_cost: 4
effective_io_concurrency: 2
synchronous_commit: on
autovacuum: on
autovacuum_max_workers: 5
autovacuum_vacuum_scale_factor: 0.01
autovacuum_analyze_scale_factor: 0.02
autovacuum_vacuum_cost_limit: 200
autovacuum_vacuum_cost_delay: 20
autovacuum_naptime: 1s
max_files_per_process: 4096
archive_mode: on
archive_timeout: 1800s
archive_command: cd .
wal_level: replica
wal_keep_segments: 130
max_wal_senders: 10
max_replication_slots: 10
hot_standby: on
hot_standby_feedback: True
wal_log_hints: on
shared_preload_libraries: pg_stat_statements,auto_explain
pg_stat_statements.max: 10000
pg_stat_statements.track: all
pg_stat_statements.save: off
auto_explain.log_min_duration: 10s
auto_explain.log_analyze: true
auto_explain.log_buffers: true
auto_explain.log_timing: false
auto_explain.log_triggers: true
auto_explain.log_verbose: true
auto_explain.log_nested_statements: true
track_io_timing: on
log_lock_waits: on
log_temp_files: 0
track_activities: on
track_counts: on
track_functions: all
log_checkpoints: on
logging_collector: on
log_statement: mod
log_truncate_on_rotation: on
log_rotation_age: 1d
log_rotation_size: 0
log_line_prefix: '%m [%p] %q%u@%d '
log_filename: 'postgresql-%a.log'
log_directory: /var/log/postgresql
initdb: # List options to be passed on to initdb
- encoding: UTF8
- locale: en_US.UTF-8
- data-checksums
pg_hba: # должен содержать адреса ВСЕХ машин, используемых в кластере
- host all all 0.0.0.0/0 md5
- host replication replicator 127.0.0.1/32 md5
- host replication replicator 10.0.2.0/24 md5
postgresql:
listen: 10.0.2.15,127.0.0.1:5432 # разное значение на всех узлах
connect_address: 10.0.2.15:5432 # разное значение на всех узлах
use_unix_socket: true
data_dir: /var/lib/postgresql/14/main
bin_dir: /usr/lib/postgresql/14/bin
config_dir: /etc/postgresql/14/main
pgpass: /var/lib/postgresql/.pgpass_patroni
authentication:
replication:
username: replicator
password: passwd
superuser:
username: postgres
password: passwd
parameters:
unix_socket_directories: /var/run/postgresql
stats_temp_directory: /var/lib/pgsql_stats_tmp
remove_data_directory_on_rewind_failure: false
remove_data_directory_on_diverged_timelines: false
# callbacks:
# on_start:
# on_stop:
# on_restart:
# on_reload:
# on_role_change:
create_replica_methods:
- basebackup
basebackup:
max-rate: '100M'
checkpoint: 'fast'
watchdog:
mode: off # Allowed values: off, automatic, required
device: /dev/watchdog
safety_margin: 5
tags:
nofailover: false
noloadbalance: false
clonefrom: false
nosync: false
# specify a node to replicate from (cascading replication)
# replicatefrom: (node name)
Назначаем права
$ sudo chown postgres:postgres -R /etc/patroni
$ sudo chmod 700 /etc/patroni
Создаем каталог, назначаем владельца
$ sudo mkdir /var/lib/pgsql_stats_tmp
$ sudo chown postgres:postgres /var/lib/pgsql_stats_tmp
Тестируем старт (сразу на двух нодах)
$ sudo -u postgres patroni /etc/patroni/patroni.yml
Должен создастся файл .pgpass_patroni, назначаем владельца, права
$ sudo chown postgres:postgres /var/lib/postgresql/.pgpass_patroni
$ sudo chmod 0600 /var/lib/postgresql/.pgpass_patroni
Создаем Sustemd Unit (на каждой ноде)
$ sudo nano /etc/systemd/system/patroni.service
[Unit]
Description=High availability PostgreSQL Cluster
After=syslog.target network.target
[Service]
Type=simple
User=postgres
Group=postgres
# Read in configuration file if it exists, otherwise proceed
EnvironmentFile=-/etc/patroni_env.conf
# Start the patroni process
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
# Send HUP to reload from patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
# only kill the patroni process, not it's children, so it will gracefully stop postgres
KillMode=process
# Give a reasonable amount of time for the server to start up/shut down
TimeoutSec=60
# Do not restart the service if it crashes, we want to manually inspect database on failure
Restart=no
[Install]
WantedBy=multi-user.target
Добавляем сервис а автозагрузку, стартуем, смотрим статус
$ sudo systemctl daemon-reload
$ sudo systemctl start patroni
$ sudo systemctl status patroni
$ sudo systemctl enable patroni
Смотрим состояние кластера
$ sudo patronictl -c /etc/patroni/patroni.yml list
Ошибка:
''== CRITICAL: system ID mismatch, node db1-2 belongs to a different cluster''
Решение: Выполнить команды
$ sudo systemctl stop patroni
$ ETCDCTL_API=2 etcdctl rm /service/postgres-cluster/initialize
$ sudo systemctl restart patroni
$ sudo systemctl status patroni
Создадим файла с настройками по умолчанию, что позволит не указывать настройки подключения для patronictl
$ sudo mkdir -p ~/.config/patroni/
$ sudo nano ~/.config/patroni/patronictl.yaml
dcs_api:
etcd://localhost:2379
namespace: /service/
scope: postgres-cluster
authentication:
username: patroni
password: passwd
Проверяем
$ patronictl show-config
$ patronictl list
Если на других нодах PostgreSQL был запущен раньше, удалите каталог данных, чтобы заработала реплика
$ sudo systemctl stop patroni
$ sudo rm -rf /var/lib/postgresql/14/main/*
$ sudo systemctl start patroni
Ошибка:
==patroni: fatal the database system is starting up
Ошибка в логах PostgreSQL: fatal the database system is starting up
Решение:
$ sudo systemctl stop patroni
$ sudo rm -rf /var/lib/postgresql/15/main/*
$ sudo systemctl start patroni
==== Установка PGbouncer (db1-1, db1-2) ====
Устанавливаем PGBouncer, правим конфиг
$ sudo apt -y install pgbouncer
$ sudo mv /etc/pgbouncer/pgbouncer.ini /etc/pgbouncer/pgbouncer.ini.origin
$ sudo nano /etc/pgbouncer/pgbouncer.ini
[databases]
postgres = host=127.0.0.1 port=5432 dbname=postgres
* = host=127.0.0.1 port=5432
[pgbouncer]
logfile = /var/log/postgresql/pgbouncer.log
pidfile = /var/run/postgresql/pgbouncer.pid
listen_addr = *
listen_port = 6432
unix_socket_dir = /var/run/postgresql
auth_type = md5
#auth_type = trust
auth_file = /etc/pgbouncer/userlist.txt
auth_user = postgres
auth_query = SELECT usename, passwd FROM pg_shadow WHERE usename=$1
#admin_users = pgbouncer, postgres
admin_users = postgres
ignore_startup_parameters = extra_float_digits,geqo,search_path
pool_mode = session
#pool_mode = transaction
server_reset_query = DISCARD ALL
max_client_conn = 10000
#default_pool_size = 20
reserve_pool_size = 1
reserve_pool_timeout = 1
max_db_connections = 1000
#max_client_conn = 900
default_pool_size = 500
pkt_buf = 8192
listen_backlog = 4096
log_connections = 1
log_disconnections = 1
# Documentation https://pgbouncer.github.io/config.html
Создадим файл userlist.txt
$ sudo nano /etc/pgbouncer/userlist.txt
"postgres" "passwd"
"pgbouncer" "passwd"
Перезапускаем PGbouncer на нодах
$ sudo systemctl restart pgbouncer
Файл /etc/pgbouncer/userlist.txt содержит имена пользователей и пароли, с которыми PGbouncer подключается к базе. Пароли не обязательно хранить в открытым виде, можно так:
...
"pgbouncer" "md576a2173be6393254e72ffa4d6df1030a"
Хэш 76a2173be6393254e72ffa4d6df1030a посчитан как MD5 от пароля
$ echo -n 'passwd' | md5sum
Тестируем
$ sudo su - postgres
$ psql -p 6432 -h 127.0.0.1 -U postgres postgres
==== Установка и настройка HAproxy (db1-1, db1-2) ====
Установим ПО
$ sudo apt -y install haproxy
Правим конфиг
db1-1:
$ sudo nano /etc/haproxy/haproxy.cfg
global
maxconn 100000
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
retries 2
timeout queue 5s
timeout connect 5s
timeout client 60m
timeout server 60m
timeout check 15s
listen stats
mode http
bind 10.0.2.15:7000
stats enable
stats uri /
listen postgres_master
bind *:5000
maxconn 10000
option tcplog
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 4 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas
bind *:5001
maxconn 10000
option tcplog
option httpchk OPTIONS /replica
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas_sync
bind *:5002
maxconn 10000
option tcplog
option httpchk OPTIONS /sync
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas_async
bind *:5003
maxconn 10000
option tcplog
option httpchk OPTIONS /async
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
db1-2:
$ sudo nano /etc/haproxy/haproxy.cfg
global
maxconn 100000
log /dev/log local0
log /dev/log local1 notice
chroot /var/lib/haproxy
stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
stats timeout 30s
user haproxy
group haproxy
daemon
defaults
mode tcp
log global
retries 2
timeout queue 5s
timeout connect 5s
timeout client 60m
timeout server 60m
timeout check 15s
listen stats
mode http
bind 10.0.2.16:7000
stats enable
stats uri /
listen postgres_master
bind *:5000
maxconn 10000
option tcplog
option httpchk OPTIONS /master
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 4 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas
bind *:5001
maxconn 10000
option tcplog
option httpchk OPTIONS /replica
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas_sync
bind *:5002
maxconn 10000
option tcplog
option httpchk OPTIONS /sync
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
listen postgres_replicas_async
bind *:5003
maxconn 10000
option tcplog
option httpchk OPTIONS /async
balance roundrobin
http-check expect status 200
default-server inter 3s fastinter 1s fall 3 rise 2 on-marked-down shutdown-sessions
server db1-1 10.0.2.15:6432 check port 8008
server db1-2 10.0.2.16:6432 check port 8008
Проверка конфига
$ sudo haproxy -f /etc/haproxy/haproxy.cfg -c
Перезапускаем HAproxy, смотрим статус
$ sudo systemctl restart haproxy
$ sudo systemctl status haproxy
Настройка отказоустойчивого кластера завершена
==== Типовые кейсы Patroni ====
Если master упал, сделать реплику лидером
$ sudo patronictl -c /etc/patroni/patroni.yml list
$ sudo patronictl -c /etc/patroni/patroni.yml failover
Candidate ['db1-1'] []: db1-1
Current cluster topology
+--------+-----------+---------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+ Cluster: postgres-cluster (7154050747629718791) --------+
| db1-1 | 10.0.2.15 | Replica | running | 9 | 16 |
+--------+-----------+---------+---------+----+-----------+
Are you sure you want to failover cluster postgres-cluster? [y/N]: y
2022-10-14 15:46:19.53515 Successfully failed over to "db1-1"
+--------+-----------+--------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+ Cluster: postgres-cluster (7154050747629718791) -------+
| db1-1 | 10.0.2.15 | Leader | running | 9 | |
+--------+-----------+--------+---------+----+-----------+
Сменить лидера
$ sudo patronictl -c /etc/patroni/patroni.yml list
$ sudo patronictl -c /etc/patroni/patroni.yml switchover
Master [db1-1]: db1-1
Candidate ['db1-2'] []: db1-2
When should the switchover take place (e.g. 2022-10-15T02:36 ) [now]: now
Current cluster topology
+--------+-----------+--------------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+ Cluster: postgres-cluster (7154050747629718791) -+-----------+
| db1-1 | 10.0.2.15 | Leader | running | 12 | |
| db1-2 | 10.0.2.16 | Sync Standby | running | 12 | 0 |
+--------+-----------+--------------+---------+----+-----------+
Are you sure you want to switchover cluster postgres-cluster, demoting current master db1-1? [y/N]: y
2022-10-15 01:36:46.92463 Successfully switched over to "db1-2"
+--------+-----------+---------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+ Cluster: postgres-cluster (7154050747629718791) --------+
| db1-1 | 10.0.2.15 | Replica | stopped | | unknown |
| db1-2 | 10.0.2.16 | Leader | running | 12 | |
+--------+-----------+---------+---------+----+-----------+
cfgadmin@db1-1:~$ sudo patronictl -c /etc/patroni/patroni.yml list
+--------+-----------+--------------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+ Cluster: postgres-cluster (7154050747629718791) -+-----------+
| db1-1 | 10.0.2.15 | Sync Standby | running | 13 | 0 |
| db1-2 | 10.0.2.16 | Leader | running | 13 | |
+--------+-----------+--------------+---------+----+-----------+
Смотрим историю переключений
$ sudo patronictl -c /etc/patroni/patroni.yml history
Отключаем авто переключение Replica-Master
sudo patronictl -c /etc/patroni/patroni.yml pause
Реинициализировать кластер
sudo patronictl -c /etc/patroni/patroni.yml reinit postgres-cluster
postgres-cluster – задается в настройках patroni (scope: …)
Реинициализировать ноду
$ sudo patronictl -c /etc/patroni/patroni.yml reinit postgres-cluster db1-2
Редактируем конфиг patroni
$ sudo patronictl -c /etc/patroni/patroni.yml edit-config
Перезапустить кластер (обычно после редактирования конфига patroni)
$ sudo patronictl -c /etc/patroni/patroni.yml restart postgres-cluster
#$ sudo patronictl -c /etc/patroni/patroni.yml reload postgres-cluster
Статусы сервисов
$ sudo patronictl -c /etc/patroni/patroni.yml list
$ etcdctl endpoint status --cluster
$ etcdctl endpoint health --cluster
$ sudo systemctl status haproxy
$ sudo systemctl status patroni
$ sudo systemctl status etcd
$ sudo systemctl status keepalived