Одна из завершающих публикаций цикла «В облако на работу:… Рецепты от Капитана» в ходе которых был собран полнофункциональный рабочий контур 1С в сети на отечественной Ред ОС. С веб-серверами, доменной авторизацией, архивированием и прочая прочая…
Это основное блюдо, на закуску разберемся с отказоустойчивостью.
В этой публикации для PostgreSQL, заодно попробуем сделать это по новому.


После романтического свидания девушка предлагает:
-Мы можем поехать к тебе и заняться кое-чем непозволительным.
-Ух ты! Будем делить на ноль!
Обрадовался программист.
anekdot.ru©



Внимание! Метод сборки отказоустойчивого кластера PostgreSQL этой публикации отличается от рекомендованного ИТС.
Кроме того, профессиональным я считаю рецепт от человека собравшего 10+ работающих по нему систем, в данном случае это не так.
Поэтому не начинайте его применение в рабочем контуре без предварительного тестирования.



Но, пока корифеи в отпуске, почему бы не заняться непозволительным и немного не пошатать их трубу.



Тем кто не любит много букв



Отказоустойчивый кластер PostgreSQL для 1С можно построить без HAProxy, используя виртуальный IP и vip-manager для управления им.



Кто не любит читать вообще, может посмотреть видео.
youtube
Остальные, добро пожаловать.



Постановка задачи



Посмотрим на знакомую схему кластера от ИТС & Co.



Ее очевидный недостаток, это лишнее звено в виде HAProxy.
Это, в любом случае, отрицательный вклад в быстродействие и слабое звено как отказоустойчивость самого узла HAProxy.
Ноги этой схемы растут из веб-приложений и там присутствие HAProxy оправдано, т.к. он разделяет трафик, если приложение это умеет, то писатели идут налево, а читатели направо и никто никому не мешает.

Учитывая, что читателей намного больше, производительность возрастает кратно.
1С же не умеет, я надеюсь пока, так работать и для нее HAProxy это просто переключатель трафика, вносящий процентов 1-10% задержки в зависимости от железа и его настроек.

И не только 1С, много приложений не могут в только чтение, отсюда и попытки различной степени успешности обхода этой проблемы, найти которые можно на любой конференции PostgreSQL.
Обычно схемы получаются весьма замысловатые, тяжелые как обслуживании, так и в понимании.

Напоминающие поход по магазину


А как было бы прекрасно. Вжух...

и все работает без этого лишнего звена.
Такое решение есть у компании CYBERTEC PostgreSQL International GmbH, у меня и теперь будет у вас.

Кстати, у них же более продвинутый PGConfigurator.
Решение это vip-manager, обеспечивающий единую точку входа (виртуальный IP адрес) для доступа к PostgreSQL.
Давайте обо всем по порядку.



Исходные данные



знакомые из предыдущих статей



  • Сервер 1С РедОС 8 
  • Postgres 16 от PostgresPro
  • 1С Предприятие 64-х 8.3.24.1467
  • все в домене test.loc. 
    Пользователь, от которого работает сервер 1С usr1cv83, пароли у всех 123456.
    Все эти значения произвольные и должны в скриптах быть заменены на ваши.
  • все по железу 4ГБ RAM 50ГБ SSD 2 Ядра CPU
  • все развернуто в облаке ©Serverspace из оригинальных iso образов производителей для чистоты эксперимента.
  • база Зарплата и управление персоналом КОРП, редакция 3.1 (3.1.29.62) демо


 





 



Чтобы статья действительно была рецептом, установим все компоненты системы с самого начала. 



etcd, обращаем внимание на версию, это будет иметь значение при конфигурации patroni



dnf install -y etcd
etcd --version
systemctl status etcd.service --no-pager -l
mv /etc/etcd/etcd.conf /etc/etcd/etcd.conf.def
mcedit /etc/etcd/etcd.conf 



берем шаблон файла настроек с ИТС или с github заменяем в нем имя кластера, адреса хостов, стартуем первый узел, добавляем в базу два других по порядку, тогда все получится с первого раза.



...
#[Member]
ETCD_DATA_DIR="/var/lib/etcd/cluster-1c"
ETCD_LISTEN_PEER_URLS="http://0.0.0.0:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379"
ETCD_NAME="red8-cln01.test.loc"
ETCD_HEARTBEAT_INTERVAL="1000"
ETCD_ELECTION_TIMEOUT="5000"
#[Clustering]
ETCD_INITIAL_ADVERTISE_PEER_URLS="http://red8-cln01.test.loc:2380" 
ETCD_ADVERTISE_CLIENT_URLS="http://red8-cln01.test.loc:2379"
ETCD_INITIAL_CLUSTER="red8-cln01.test.loc=http://red8-cln01.test.loc:2380" 
# для собранного кластера ETCD_INITIAL_CLUSTER="red8-cln01.test.loc=http://red8-cln01.test.loc:2380, red-srv.test.loc=http://red-srv.test.loc:2380, red8-srv.test.loc=http://red8-srv.test.loc:2380" 
ETCD_INITIAL_CLUSTER_TOKEN="cluster-1c"
ETCD_INITIAL_CLUSTER_STATE="new"
# для собранного кластера ETCD_INITIAL_CLUSTER_STATE="existing"


systemctl start etcd.service
systemctl status etcd.service --no-pager -l

etcdctl member add red8-srv.test.loc --peer-urls=http://red8-srv.test.loc:2380

#настраиваем conf файл на добавленном сервере и стартуем на нем службу
etcdctl member add red-srv.test.loc --peer-urls=http://red-srv.test.loc:2380
#настраиваем conf файл на добавленном сервере и стартуем на нем службу
#проверяем работоспособность всех узлов




ENDPOINTS=red8-cln01.test.loc:2379,red-srv.test.loc:2379,red8-srv.test.loc:2379
etcdctl --endpoints=$ENDPOINTS endpoint health
etcdctl --write-out=table --endpoints=$ENDPOINTS endpoint status




кластер etcd собирается без особых проблем и работает надежно, недаром его использует Kubernetes, если что-то идет не так, останавливаем службу, удаляем каталог ETCD_DATA_DIR="/var/lib/etcd/cluster-1c" и начинаем сначала



В рабочем контуре, нужно еще создать пользователя root для ограничения доступа к etcd и задать для него пароль.



patroni, при рекомендациях начинать с пустого кластера postgreSQL, Patroni нормально установится и примет уже существующий, это сэкономит время на возню с архивами, единственно, что потребуется, это добавить пользователей для репликации Patroni superuser etc.
Дальнейшая установка описана, как на официальном сайте, так и на ИТС



python3 -m pip install patroni[etcd]
dnf install python3-psycopg2 -y
mkdir /etc/patroni
chown postgres:postgres /etc/patroni
chmod 700 /etc/patroni
mcedit '/1c/create users.txt'

chmod +777 -R /1c



...

 



— Patroni superuser
— Replace PATRONI_SUPERUSER_USERNAME and PATRONI_SUPERUSER_PASSWORD accordingly
CREATE USER patroni_superuser WITH SUPERUSER ENCRYPTED PASSWORD '123456';



— Patroni replication user
— Replace PATRONI_REPLICATION_USERNAME and PATRONI_REPLICATION_PASSWORD accordingly
CREATE USER patroni_replication WITH REPLICATION ENCRYPTED PASSWORD '123456';



— Patroni rewind user, if you intend to enable use_pg_rewind in your Patroni configuration
— Replace PATRONI_REWIND and PATRONI_REWIND_PASSWORD accordingly
CREATE USER patroni_rewind WITH ENCRYPTED PASSWORD '123456';
GRANT EXECUTE ON function pg_catalog.pg_ls_dir(text, boolean, boolean) TO patroni_rewind;
GRANT EXECUTE ON function pg_catalog.pg_stat_file(text, boolean) TO patroni_rewind;
GRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text) TO patroni_rewind;
GRANT EXECUTE ON function pg_catalog.pg_read_binary_file(text, bigint, bigint, boolean) TO patroni_rewind;




После этого службу postgres нужно остановить и выключить
systemctl status postgrespro-1c-16.service
systemctl stop postgrespro-1c-16.service
systemctl disable postgrespro-1c-16.service
mcedit /etc/systemd/system/patroni.service



...

 [Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target
[Service]
Type=simple
User=postgres
Group=postgres
ExecStart=/usr/local/bin/patroni /etc/patroni/patroni.yml
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=process
TimeoutSec=30
Restart=no
[Install]
WantedBy=multi-user.target




mcedit /etc/patroni/patroni.yml
Шаблон файла конфигурации можно также взять с ИТС или сайта разработчика, а можно командой
patroni --generate-sample-config /etc/patroni/patroni.yml



...

scope: 'cluster-1c'
name: red8-srv.test.loc
namespace: /db/




log:
  format: '%(asctime)s %(levelname)s: %(message)s'
  level: INFO
  max_queue_size: 1000
  traceback_level: ERROR



restapi:
  connect_address: red8-srv.test.loc:8008
  listen: 0.0.0.0:8008



etcd3:
  host: red8-srv.test.loc:2379
  username: root
  password: '123456'



# The bootstrap configuration. Works only when the cluster is not yet initialized.
# If the cluster is already initialized, all changes in the `bootstrap` section are ignored!
bootstrap:
  # This section will be written into <dcs>:/<namespace>/<scope>/config after initializing
  # new cluster and all other cluster members will use it as a `global configuration`.
  # WARNING! If you want to change any of the parameters that were set up
  # via `bootstrap.dcs` section, please use `patronictl edit-config`!
  dcs:
    loop_wait: 10
    retry_timeout: 10
    ttl: 30
    postgresql:
      parameters:
        hot_standby: 'on'
        max_connections: 100
        max_locks_per_transaction: 64
        max_prepared_transactions: 0
        max_replication_slots: 10
        max_wal_senders: 10
        max_worker_processes: 8
        track_commit_timestamp: 'off'
        wal_keep_size: 128MB
        wal_level: replica
        wal_log_hints: 'on'
      use_pg_rewind: true
      use_slots: true



postgresql:
  authentication:
   superuser:
    username: patroni_superuser
    password: '123456'
   replication:
    username: patroni_replication
    password: '123456'
   rewind:
    username: patroni_rewind
    password: '123456'
  bin_dir: '/opt/pgpro/1c-16/bin/'
  connect_address: red8-srv.test.loc:5432
  data_dir: /var/lib/pgpro/1c-16/data
  listen: 0.0.0.0:5432
  parameters:
    password_encryption: md5



tags:
  clonefrom: true
  failover_priority: 1
  noloadbalance: false
  nosync: false
 




в нем изменяем адреса серверов, имя кластера и т.п
т.к. у нас etcd третьей версии то его настройки надо задавать в разделе etcd3
проверяем, что нигде не опечатались и корректно расставили отступы



/usr/local/bin/patroni --validate-config /etc/patroni/patroni.yml
mcedit /var/lib/pgpro/1c-16/data/pg_hba.conf

 



...

host    all             all             0.0.0.0/0               md5
host    replication     all             0.0.0.0/0               md5
#проверяем наличие этих строк для доступа к лидеру с реплики




systemctl start patroni.service
systemctl status patroni.service --no-pager -l



Далее идут примеры команд которыми можно управлять кластером, посмотреть его настройки, состояние etc.

По поводу какие настройки где задаются, лучше почитать на сайте разработчика, все очень доходчиво рассказано. Сломать вы ничего не сломаете, т.к. самые важные для patroni задаются как значения командной строки запуска postgres и имеют наивысший приоритет.
/usr/local/bin/patronictl --config-file /etc/patroni/patroni.yml topology cluster-1c
/usr/local/bin/patronictl --config-file /etc/patroni/patroni.yml edit-config cluster-1c --pg max_locks_per_transaction="256" --force



/usr/local/bin/patronictl --config-file /etc/patroni/patroni.yml restart cluster-1c



итог установки: работающий кластер с лидером и репликой



haproxy, т.к мы идем по инструкции ИТС, то устанавливаем его на отдельный сервер
yum install -y haproxy
mv /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.conf.def
mcedit /etc/haproxy/haproxy.cfg

 



...

global
 maxconn 1000
defaults
 log global
 mode tcp
 retries 2
 timeout client 30m
 timeout connect 4s
 timeout server 30m
 timeout check 5s
listen stats
 mode http
 bind *:7000
 stats enable
 stats uri /
listen postgres
 bind *:5432
 option httpchk
 http-check expect status 200
 default-server inter 3s fastinter 1s fall 2 rise 2 on-marked-down shutdown-sessions
 server red8-srv.test.loc red8-srv.test.loc:5432 maxconn 100 check port 8008
 server red-srv.test.loc red-srv.test.loc:5432 maxconn 100 check port 8008

 




...

В благословенные времена, когда семинары проходили не онлайн, а в конференц-холлах, обязательно на галерке сидел технически продвинутый человек, который рвал на себе волосы показывая пальцем в докладчика и тихим шепотом советуя так не делать.
Причем иногда количество волос на голове этого человека намекало, на скольки конференциях он уже побывал.




проверяем файл конфигурации на наличие опечаток и корректность отступов
/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c



systemctl start haproxy.service
systemctl status haproxy.service --no-pager -l



Можем посмотреть статус по адресу имя сервера:7000



И идем делать тесты.
На лидере создаем и инициализируем базу pgbench.
sudo -u postgres psql -U postgres -c "create database pgbench;"
PGPASSWORD='123456' pgbench -h redos-vm -U postgres -i -s 5 pgbench



Затем с клиента проверяем по прямому соединению на лидер   



PGPASSWORD='123456' pgbench  -h red-srv.test.loc -U postgres -c 10 -j 1 -t 10000 pgbench




и через HAProxy
PGPASSWORD='123456' pgbench  -h red8-cln01.test.loc -U postgres -c 10 -j 1 -t 10000 pgbench



Переключаем соединение базы 1С на адрес HAProxy



В облаке ©Serverspace разница получилась не очень большая, в других контурах где удалось проверить, доходило до 10%, кто проверит у себя, пишите в комментариях.



vip-manager, устанавливаем на сервера patroni
пакет берем с github Releases



echo "net.ipv4.ip_nonlocal_bind = 1"  >> /etc/sysctl.conf
sysctl -p

rpm -ivh *.rpm
systemctl start vip-manager.service
systemctl status vip-manager.service --no-pager -l
systemctl enable vip-manager.service
cp  /etc/default/vip-manager.yml  /etc/default/vip-manager.yml.bak



mcedit /etc/default/vip-manager.yml



...

 



# время проверки в миллисекундах
interval: 1000



# <namespace>/<scope>/leader из конфигурации Patroni
trigger-key: "/db/cluster-1c/leader"
# hostname сервера
trigger-value: "red8-srv.test.loc"



ip: 10.0.0.10 # virtual ip 
netmask: 24 # netmask
interface:  enp0s5 #interface 



hosting-type: basic 



dcs-type: etcd 
# список DCS endpoints
dcs-endpoints:
  — 127.0.0.1:2379



#etcd-user: "patroni"
#etcd-password: "123456"



retry-num: 2
retry-after: 250  #in milliseconds



verbose: false
 




Прописываем виртуальный адрес в DNS или файлах hosts



после этого можем переключать на него соединение базы 1С, HAProxy можно отключать.
Допускаю, что не понимаю пока его истинной ценности для 1С.
Расскажите об этом в комментариях.

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



Благодарности:
Благодарю компанию ©Serverspace за предоставленное оборудование, без поддержки собрать такой пингвинариум мне было бы негде.



Главный спонсор этой публикации, питерская погода.

А вы как думаете, почему наш город дал миру столько великих ученых и писателей?




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



...

Письмо в редакцию журнала "Работница".
Дорогая редакция! Помогите пожалуйста, что мне делать, муж не дает покою.
И на кухне пристает и у телевизора, а уж когда пол мою, то вообще кошмар.
Просит отдать супружеский долг.
Вот и сейчас…, извините за неровный почерк.
anekdot.ru©






Ну и заодно, возможно главный спонсор всех нас, кроме тех, кого нашли в капусте, ведь чинить людей, это посложнее, чем чинить компьютеры.
16 июня 2024 День медицинского работника (День медика)

Давайте помнить и уважать медиков не только один день в году.
Как минимум, пропустите скорую, даже если она едет без сирены, возможно это спасет чью-то жизнь.
Мой почет и уважение всем и отдельно тех. отделу ПСПбГМУ.



Планы на будущее:



Дописать про отказоустойчивый кластер уже для 1С.
+ нагрузочное тестирование, оно есть у меня



Уйти в лето.



Желающие знают где меня искать, время за пределами рабочего.





 



Статья продолжает серию публикаций:





Серия "Рецепты от Капитана" на всякий случай





 

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


  1. schernolyas
    17.06.2024 12:23

    неужели "active-active" кластер? или просто очередной костыль для некластеризуемого PostgreSQL community edition ?


    1. capitannemo Автор
      17.06.2024 12:23

      "active-active" кластер 1С не умеет

      но это не костыль

      PostgreSQL community edition это что за зверь?


      1. schernolyas
        17.06.2024 12:23

        "PostgreSQL community edition это что за зверь? " <-- дык ... это обычный postgres. просто есть компании которые делают свои расширения и они платные. Соответственно, вместо всего этого зоопарка вы могли просто поставить какой-нибуть платный PostgreSQL PRO ... и получить active-active кластер из коробки. ну ... типа того

        Вообще .... все попытки построить что-то на базе PostgreSQL community edition ... это как тюнить запорожец в надежде получить болид Формулы 1. Нужно смотреть в сторону кластеризуемых решений на базе NewSQL. cockroachdb, yugabytedb и т.д.

        Извините если обидел.


        1. capitannemo Автор
          17.06.2024 12:23

          PostgreSQL PRO мультимастер тоже не поддерживает 1С или наоборот
          Вообще нет данных про active-active кластер PostgreSQL для 1С

          NewSQL. cockroachdb, yugabytedb и т.д. тоже 1С не поддерживает

          Никаких обид

          А в чем зоопарк то? Postgres Patroni etcd вроде ничего навороченного


          1. schernolyas
            17.06.2024 12:23

            "А в чем зоопарк то?" ну .... просто много разных компонент :-) схема масштабная.

            Если у 1с и active-active кластеров такая взаимная неприязнь .... ну я не знаю как это прокоментировать. нормальных слов у меня нет.


            1. capitannemo Автор
              17.06.2024 12:23

              Скорее всего допилят либо те либо другие, просто раньше это было не актуально.
              Да и в принципе это для 1С не так актуально, т.к. основная нагрузка идет на сервер приложений 1С, он поддерживает active-active и балансировку, а СУБД гораздо меньше нагружена, там важнее просто отказоустойчивость


              1. schernolyas
                17.06.2024 12:23

                ну .... time will tell


  1. itGuevara
    17.06.2024 12:23

    Можете привести расчет надежности своего "отказоустойчивого кластера"? Или подобного. Включая состояние "отказ, необнаруженный внутренней системой управления кластера".


    1. capitannemo Автор
      17.06.2024 12:23

      Надежность определяется всеми компонентами, а у меня пример построения, это разные вещи.
      По крайней мере в ней нет единой точки отказа


  1. podvox23
    17.06.2024 12:23

    Не проще на pacemaker кластер собрать?


    1. capitannemo Автор
      17.06.2024 12:23

      Если есть пример для PostgreSQL  буду признателен за ссылку


  1. starik-2005
    17.06.2024 12:23

    Дверь в лето - лучшая фантастика про кота )))

    Остальное прочитал по диагонали и не понял )))


    1. capitannemo Автор
      17.06.2024 12:23

      Лучший комментарий)


  1. Roman2dot0
    17.06.2024 12:23

    Вместо vip и haproxy можно использовать встроенный в libpq функционал.
    Указать несколько серверов в строке подключения, задать target_session_args, там же и балансировка простая есть (для чтения).
    Вот тут кратко.


    1. capitannemo Автор
      17.06.2024 12:23

      Совет интересный, но не факт что он сработает в 1С.

      Там если видели прописывается 1 сервер СУБД и я пока не представляю как второй подставить и самое главное как сервер 1С будет переключаться

      На это только разработчики платформы могут ответить


  1. Naves
    17.06.2024 12:23
    +2

    Вы сами-то проверяли отказоустойчивость?
    Запустите какую-нибудь обработку, которая будет писать или обновлять данные.
    Выключите мастер-сервер, включите его.

    После старта бд старого мастера, теперь выключите новый мастер.

    А теперь ищите нового мастера... и посмотрите что и где пропало.

    А теперь повторите эксперимент с базой размером больше 500гб

    Я вот пробовал все это, результат не понравился. Часть данных пропала (я знаю про синхронную репликацию, а автор статьи?) Старый мастер начал пытаться стать репликой нового мастера и не смог. Да, у меня руки кривые, но где тогда надежность.


    1. capitannemo Автор
      17.06.2024 12:23

      Безусловно проверял. Я бы не стал обманывать столь уважаемую аудиторию хабражителей.
      Чуть позже подъедет видео, там будет видно как проходит свитчовер и база не рушится.
      И в планах записать полноценное нагрузочное тестирование.

      Дело не в размере базы, а в том насколько плотно в ней работают пользователи и успевает ли реплика за лидером
      Пропадет то что было в транзакции, аналогично как бы оно пропало при разрыве сети.

      По поводу больших баз уже писал, это не повод для хвастовства, а повод присмотреться все ли корректно.

      Есть простое как гвоздь эмпирическое правило: Если база не сворачивается, она наворачивается.