#1671: Как настроить Swarmica в режиме повышенной отказоустойчивости?

Отредактирована: 81 день назад

Симптомы

Все системы у нас в компании должны быть развернуты в режиме повышенной отказоустойчивости, можем ли мы вынести базу данных на отдельный сервер?

Можем ли мы использовать отказоустойчивый кластер БД для Swarmica?

Можно ли настроить Swarmica в режиме active-active cluser?

Решение

Рекомендуемое решение

Наиболее оптимальным решением, с точки зрения стоимости обслуживания, влияния на производительность системы, а так же показателей восстановления RTO (Recovery Time Objective, целевое время восстановления работы) / RPO (Recovery Point Objective, максимальный допустимый объем потерянных данных) является размещение Swarmica внутри единой виртуальной машины, виртуальный диск которой расположен на сетевом хранилище с необходимыми настройками репликации и отказоустойчивости.

Таким образом, минимизируются накладные расходы на развертывание и обслуживание системы и обеспечиваются целевые показатели отказоустойчивости.

Вынос БД в отдельный сервер с репликацией

Данная конфигурация не является рекомендованной и поддерживаемой: такая схема не проходит регулярное тестирование командой Swarmica. Особенности и риски:

  • Данная конфигурация не обеспечивает отказоустойчивости сервера БД в полной мере, т.к. в режиме репликации если Мастер станет недоступен, то Реплика не станет Мастером автоматически - ее надо будет сделать Мастером вручную.
  • Стоит учитывать ухудшение производительности за счет появления сетевого лага между сервером приложения Swarmica и сервером БД.
  • Добавляется потенциальная точка отказа.

Для данной конфигурации нужны 2 сервера:

-Сервер Swarmica (Ubuntu 24)
-Сервер Postgresql-1 (Ubuntu 24)
-Сервер Postgresql-2 (Ubuntu 24)

Postgresql-1 выступает в роли Мастер сервера, а Postgresql-2 в роли реплики.

1. На сервере Swarmica установите Swarmica по инструкции

2. После установки создайте резервную копию БД как описано здесь

3. Остановите Swarmica:

cd /root/swarmica
docker compose down

4. Создайте резервную копию файла /root/swarmica/docker-compose.yml

cp /root/swarmica/docker-compose.yml{,.orig}

5. Закомментируйте спецификацию сервиса postgres и строки описывающие зависимость от сервиса postgres в файле /root/swarmica/docker-compose.yml:

volumes:
  swarmica_ai_assistant: {}
  swarmica_logs: {}
#  swarmica_postgres_data_backups: {}
#  swarmica_postgres_data: {}
  swarmica_runtime: {}
<...>
  django: &django
    image: reg.gl.swd.im/swarmica/backend:${SW_BACKEND_VERSION}
    depends_on:
#      - postgres
<...>
#  postgres:
#    image: postgres:14.2-bullseye
#    container_name: swarmica-postgres
#    shm_size: 1gb
#    command: postgres -N 200 -c work_mem=8MB -c temp_buffers=16MB -c shared_buffers=1GB -c track_activity_query_size=16384
#    restart: always
#    volumes:
#      - swarmica_postgres_data:/var/lib/postgresql/data:Z
#      - swarmica_postgres_data_backups:/backups:z
#    env_file:
#      - .env
<...>
  celeryworker:
    <<: *django
    depends_on:
#      - postgres
      - redis
<...>
  celerybeat:
    <<: *django
    restart: always
    depends_on:
#      - postgres
      - redis
<...>

6. В файле /root/swarmica/.env измените:

POSTGRES_HOST=postgres

на

POSTGRES_HOST=<IP_ADDRESS>

где <IP_ADDRESS> - IP адрес сервера Postgresql

и запустите Swarmica:

docker compose pull && docker compose up -d

7. На обоих Postgresql серверах установите postgresql-14:

sudo apt install curl ca-certificates -y
sudo install -d /usr/share/postgresql-common/pgdg
sudo curl -o /usr/share/postgresql-common/pgdg/apt.postgresql.org.asc --fail https://www.postgresql.org/media/keys/ACCC4CF8.asc
sudo sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/postgresql-common/pgdg/apt.postgresql.org.asc] https://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
sudo apt update
sudo apt install postgresql-14 postgresql-contrib-14 -y

8. На обоих серверах авторизуйтесь как пользователь postgres и создайте пользователя и БД для Swarmica:

su - postgres
psql
CREATE USER swarmica_user WITH PASSWORD '<PASSWORD>';
CREATE DATABASE swarmica_app OWNER swarmica_user;
GRANT ALL PRIVILEGES ON DATABASE swarmica_app TO swarmica_user;
quit
exit

где <PASSWORD> - пароль БД из файла /root/swarmica/.env с сервера Swarmica.

9. На Postgresql-1 загрузите резервную копию БД из шага 2 и восстановите ее:

pg_restore --if-exists --clean -U swarmica_user -d swarmica_app <PATH-TO-BACKUP.sql> 

где <PATH-TO-BACKUP.sql> - путь до загруженной резервной копии БД.

10. На Postgresql-1 измените файл конфигурации /etc/postgresql/14/main/postgresql.conf, чтобы postgresql был доступен извне и добавьте конфигурацию Мастер сервера:

listen_addresses = '*'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 5
hot_standby = on

11. Добавьте в файл /etc/postgresql/14/main/pg_hba.conf строку:

host    swarmica_app    swarmica_user    <IP>/<MASK>                 md5
host    replication     repuser          <REPLICA_IP>/<REPLICA_MASK> md5

где <IP> - IP адрес Swarmica сервера, <MASK> - маска подсети, <REPLICA_IP> - IP адрес сервера Postgresql-2 и <REPLICA_MASK> - его маска подсети.

12. Создайте пользователя для репликации:

sudo -u postgres psql -c "CREATE ROLE repuser REPLICATION LOGIN PASSWORD 'your_secure_password';"

13. Перезапустите postgresql на Postgresql-1:

systemctl restart postgresql@14-main

14. На Postgresql-2 остановите postgresql:

systemctl stop postgresql@14-main

15. Очистите папку с данными:

sudo rm -rf /var/lib/postgresql/14/main/*

16. Скопируйте данные с Postgresql-1:

sudo -u postgres pg_basebackup -h <IP_Мастера> -U repuser -D /var/lib/postgresql/14/main/ -P -R -v

17. Запустите posgresql на Postgresql-2:

systemctl start postgresql@14-main

Вынос БД в отдельный сервер + отказоустойчивость

Данная конфигурация не является рекомендованной и поддерживаемой: такая схема не проходит регулярное тестирование командой Swarmica. Особенности и риски:

  • Стоит учитывать ухудшение производительности за счет появления сетевого лага между сервером приложения Swarmica и сервером БД
  • Увеличение энтропии системы и, как следствие, увеличение сложности обслуживания
  • Добавление потенциальных точек отказа

Для данной конфигурации нужны 4 сервера:

-Сервер swarmica-master-1 (Ubuntu 24)
-Сервер swarmica-postgres-1 (Ubuntu 24)
-Сервер swarmica-postgres-2 (Ubuntu 24)
-Сервер swarmica-pgbouncer-1 (Ubuntu 24)

swarmica-master-1

Повторите шаги 1-6 этой секции, но на 6 шаге измените строки:

POSTGRES_HOST=postgres
POSTGRES_PORT=5432

на:

POSTGRES_HOST=<PGBOUNCER_IP>
POSTGRES_PORT=6432

где <PGBOUNCER_IP> - IP адрес сервера swarmica-pgbouncer-1

swarmica-pgbouncer-1

На данном сервере настраивается приложение pgbouncer + haproxy. Данная связка позволяет реализовать механизм failover, когда Мастер сервер базы данных станет недоступным.

1. Установите docker:

apt install docker.io docker-compose-v2

2. Создайте папку /root/swarmica-pgbouncer и перейдите в нее:

mkdir /root/swarmica-pgbouncer
cd /root/swarmica-pgbouncer

3. Создайте файл /root/swarmica-pgbouncer/docker-compose.yml со следующим содержимым:

version: "3.8"

services:
  haproxy:
    image: haproxy:2.9
    container_name: haproxy
    restart: always
    ports:
      - "5433:5433"
      - "8404:8404"
    volumes:
      - ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro

  pgbouncer:
    image: edoburu/pgbouncer
    container_name: pgbouncer
    restart: always
    ports:
      - "6432:6432"
    volumes:
      - ./pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
      - ./users/userlist.txt:/etc/pgbouncer/userlist.txt:ro

4. Создайте файл /root/swarmica-pgbouncer/haproxy.cfg со следующим содержимым:

global
  maxconn 10000

defaults
  mode tcp
  timeout connect 5s
  timeout client  1m
  timeout server  1m

# =========================
# Patroni API checks
# =========================
frontend pgsql_write
  bind *:5433
  default_backend pg_primary

backend pg_primary
  option httpchk GET /master
  http-check expect status 200

  server pg1 <swarmica-postgres-1_IP>:5432 check port 8008
  server pg2 <swarmica-postgres-2_IP>:5432 check port 8008

# =========================
# metrics
# =========================
listen stats
  bind *:8404
  stats enable
  stats uri /

где <swarmica-postgres-1_IP> IP адрес swarmica-postgres-1 и <swarmica-postgres-2_IP> - IP адрес swarmica-postgres-2.

5. Создайте файл /root/swarmica-pgbouncer/pgbouncer.ini со следующим содержимым:

[databases]
swarmica_app = host=<swarmica-pgbouncer-1_IP> port=5433 dbname=swarmica_app

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432

auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt
pool_mode = transaction

max_client_conn = 2000
default_pool_size = 50

ignore_startup_parameters = extra_float_digits

6. Создайте файл /root/swarmica-pgbouncer/users/userlist.txt со следующим содержимым:

"swarmica_user" "<DB_PASSWORD>"

где <DB_PASSWORD> - пароль БД из файла /root/swarmica/.env с сервера swarmica-master-1

7. Запустите приложение:

docker compose pull && docker compose up -d

swarmica-postgres-1 и swarmica-postgres-2

На этих серверах устанавливаются postgresql-14, etcd и patroni. Один из серверов выступает в роли Мастера, второй в роли Реплики. Связка etcd + patroni обеспечивает механизм failover. Если Мастер сервер вдруг станет недоступен, то patroni сделает Реплику Мастером, а старый Мастер станет Репликой, когда вернется в рабочее состояние.

1. Установите на обоих серверах postgresql-14 (п.7-11 этой секции)

2. На swarmica-postgres-1 установите пароль для пользователя postgres и создайте пользователя для репликации:

su - postgres
psql -c "ALTER ROLE postgres PASSWORD '<POSTGRES_PASSWORD>';"
psql -C "CREATE ROLE replication_user WITH REPLICATION LOGIN PASSWORD 'REPLICATION_PASSWORD';"
exit

3. На swarmica-postgres-1 восстановите резервную копию БД (п.12 этой секции). На swarmica-postgres-2 восстанавливать резервную копию не надо.

4. На обоих серверах остановите и выключите postgresql:

systemctl stop postgresql@14-main && systemctl disable postgresql@14-main

Это необходимо поскольку дальше управлять БД будет patroni.

5. На обоих серверах установите etcd:

apt install etcd-server etcd-client

6. Создайте файл /etc/systemd/system/etcd.service со следующим содержимым:

swarmica-postgres-1:

[Unit]
Description=etcd
After=network.target network-online.target
Wants=network-online.target

[Service]
Type=notify
User=etcd

ExecStart=/usr/bin/etcd \
  --name pg1 \
  --data-dir /var/lib/etcd \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://<swarmica-postgres-1_IP>:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://<swarmica-postgres-1_IP>:2380 \
  --initial-cluster pg1=http://<swarmica-postgres-1_IP>:2380,pg2=http://<swarmica-postgres-2_IP>:2380 \
  --initial-cluster-state new \
  --initial-cluster-token postgres-cluster

Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

swarmica-postgres-2:

[Unit]
Description=etcd
After=network.target network-online.target
Wants=network-online.target

[Service]
Type=notify
User=etcd

ExecStart=/usr/bin/etcd \
  --name pg2 \
  --data-dir /var/lib/etcd \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://<swarmica-postgres-2_IP>:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://<swarmica-postgres-2_IP>:2380 \
  --initial-cluster pg1=http://<swarmica-postgres-1_IP>:2380,pg2=http://<swarmica-postgres-2_IP>:2380 \
  --initial-cluster-state existing \
  --initial-cluster-token postgres-cluster

Restart=always
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target

Замените <swarmica-postgres-1_IP> и <swarmica-postgres-2_IP> соответственно.

7. Запустите etcd сначала на swarmica-postgres-1, потом на swarmica-postgres-2:

systemctl daemon-reload
systemctl enable etcd --now

И проверьте, что кластер etcd запустился:

etcdctl member list

Пример ожидаемого вывода:

$ etcdctl member list
c9104917e339b5d, started, pg1, http://10.130.0.33:2380, http://10.130.0.33:2379, false
e8205d05fd4e969, started, pg2, http://10.130.0.27:2380, http://10.130.0.27:2379, false

8. Установите необходимые пакеты для patroni на обоих серверах:

apt install python3 python3-pip python3-dev pipx -y

9. Авторизуйтесь под пользователем postgres и установите patroni на обоих серверах:

su - postgres
pipx ensurepath
source ~/.bashrc
pipx install patroni[psycopg2-binary,etcd]
exit

10. Создайте файл /etc/systemd/system/patroni.service на обоих серверах с содержимым:

[Unit]
Description=High availability PostgreSQL cluster
After=syslog.target network.target etcd.service

[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/var/lib/postgresql/.local/bin/patroni /etc/patroni/patroni.yml
KillMode=process
TimeoutSec=30
Restart=no

[Install]
WantedBy=multi-user.target

11. Создайте файл конфигурации /etc/patroni/patroni.yml на обоих серверах.

swarmica-postgres-1:

scope: pg-cluster
namespace: /db/
name: pg1

restapi:
  listen: 0.0.0.0:8008
  connect_address: <swarmica-postgres-1_IP>:8008                             # здесь надо указать соответствующий IP

etcd3:
  hosts: ["<swarmica-postgres-1_IP>:2379", "<swarmica-postgres-2_IP>:2379"]  # здесь надо указать соответствующие IP

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10

    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 1GB

  initdb:
    - encoding: UTF8
    - data-checksums

  pg_hba:
    - host replication replication_user <NETWORK>/<MASK> md5    # здесь указываем нужные сеть и маску подсети
    - host all all 0.0.0.0/0 md5

postgresql:
  listen: 0.0.0.0:5432
  connect_address: <swarmica-postgres-1_IP>:5432                # здесь надо указать соответствующий IP 

  data_dir: /var/lib/postgresql/14/main

  bin_dir: /usr/lib/postgresql/14/bin

  authentication:
    replication:
      username: replication_user
      password: <REPLICATION_PASSWORD>
    superuser:
      username: postgres
      password: <POSTGRES_PASSWORD>

  pg_hba:
    - host replication replication_user <NETWORK>/<MASK> md5    # здесь указываем нужные сеть и маску подсети
    # Keep your other existing pg_hba lines below
    - host all all 0.0.0.0/0 md5

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

swarmica-postgres-2:

scope: pg-cluster
namespace: /db/
name: pg2

restapi:
  listen: 0.0.0.0:8008
  connect_address: <swarmica-postgres-2_IP>:8008                            # здесь надо указать соответствующий IP

etcd3:
  hosts: ["<swarmica-postgres-1_IP>:2379", "<swarmica-postgres-2_IP>:2379"] # здесь надо указать соответствующие IP

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10

    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: "on"
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 1GB

  initdb:
    - encoding: UTF8
    - data-checksums

  pg_hba:
    - host replication replication_user <NETWORK>/<MASK> md5       # здесь указываем нужные сеть и маску подсети
    - host all all 0.0.0.0/0 md5

postgresql:
  listen: 0.0.0.0:5432
  connect_address: <swarmica-postgres-2_IP>:5432                   # здесь надо указать соответствующий IP

  data_dir: /var/lib/postgresql/14/main

  bin_dir: /usr/lib/postgresql/14/bin

  authentication:
    replication:
      username: replication_user
      password: <REPLICATION_PASSWORD>
    superuser:
      username: postgres
      password: <POSTGRES_PASSWORD>

  pg_hba:
    - host replication replication_user <NETWORK>/<MASK> md5      # здесь указываем нужные сеть и маску подсети
    # Keep your other existing pg_hba lines below
    - host all all 0.0.0.0/0 md5

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

Будьте внимательны при создании конфигурационных файлов. Вместо <REPLICATION_PASSWORD> и <POSTGRES_PASSWORD> укажите пароли из п. 2

12. Запустите patroni сначала на swarmica-postgres-1 и через 5-10 секунд на swarmica-postgres-2:

systemctl daemon-reload
systemctl enable patroni --now

13. Проверьте работоспособность patroni:

sudo -u postgres -i patronictl -c /etc/patroni/patroni.yml list

Ожидаемый вывод команды:

+ Cluster: pg-cluster (7644156829524943409) -+----+-------------+-----+------------+-----+
| Member | Host        | Role    | State     | TL | Receive LSN | Lag | Replay LSN | Lag |
+--------+-------------+---------+-----------+----+-------------+-----+------------+-----+
| pg1    | 10.130.0.33 | Leader  | running   |  6 |             |     |            |     |
| pg2    | 10.130.0.27 | Replica | streaming |  6 |   0/F742FF0 |   0 |  0/F742FF0 |   0 |
+--------+-------------+---------+-----------+----+-------------+-----+------------+-----+

Active-active кластер Swarmica

Кластер с двумя активными инстансами Swarmica не поддерживается