I.3. pg_cluster#
I.3. pg_cluster #
I.3.1. Обзор #
Версия: 1.6.0
Этот раздел описывает, как развернуть pg_cluster с использованием автоматизированных инструментов на базе ansible. В следующем тексте будут представлены примеры команд, которые необходимо ввести в терминале для подготовки SSH-сессии, проверки правильности настроек ansible и запуска playbook. В качестве пользователя будет использоваться учетная запись admin_user. При запуске команд в окружении Клиента этот пользователь должен быть изменен на учетную запись, которая имеет доступ по SSH без пароля ко всем серверам (виртуальным машинам), указанным в файле my_inventory, а также доступ к привилегированному режиму (root). В результате работы playbook на серверах, указанных в файле my_inventory, будет развернут кластер выбранной СУБД (Tantor SE-1C или PostgreSQL), управляемый через patroni.
I.3.3. Требования #
Плейбук требует установки компонентов следующих версий:
Ansible >= 2.9.10 (с коллекциями community.general, community.postgresql, community.crypto)
Python3 (с модулем pip) >= 3.10.0
psycopg2 >= 2.5.1 (рекомендуется устанавливать через pip)
packaging >= 24 (рекомендуется устанавливать через pip)
I.3.4. Подготовка Ansible #
Подготовка к запуску выполняется на узле, с которого будет запущен ansible-playbook, и включает следующие шаги:
Установить ansible
sudo python3 -m pipX.X install ansible==X.X.X # where X.X(.X) represents the version of pip and Ansible specified in the Requirements block of the current instruction.
В файле
inventory/group_vars/keepalived.ymlизмените значение переменнойcluster_vip_1на IP, который будет использоваться keepalived для выделенного виртуального адреса — единой точки входа в кластер СУБД.Заполните файл конфигурации
inventory/opt/pg_cluster/inventory/my_inventory, содержащий список хостов и их IP-адресов.
После заполнения файла my_inventory рекомендуется убедиться, что все серверы доступны для подключения к ним через SSH с помощью нужного пользователем. Для этого выполните следующую команду в терминале:
ansible all -i inventory/my_inventory -m ansible.builtin.setup -a "filter=ansible_hostname" -u admin_user
Результатом выполнения вышеуказанной команды будет ответ от каждого из доступных серверов (виртуальных машин) в следующем формате:
<hostname_from_inventory_file> | SUCCESS => {
"ansible_facts": {
"ansible_hostname": "<device_hostname>",
"discovered_interpreter_python": "/usr/bin/<host_python_version>"
},
"changed": false
}
Этот вывод для каждого сервера, описанного в файле
my_inventory, означает успешное подключение
к нему через SSH. Если в результате ответа с какого-либо сервера
(виртуальной машины) сообщение отличается от приведенного выше шаблона -
проверьте, возможно ли подключение к нему с помощью ключа от
имени пользователя, переданного с использованием флага -u. Если необходимо подключаться только с вводом пароля (без использования ключей) -
необходимо добавить флаги -kK к запуску команды и ввести пароль для подключения по SSH
(флаг -k) и для перехода пользователя в привилегированный режим (root) (флаг -K).
Обратите внимание на значение переменной
ansible_hostname в выводе команды.
Если значение localhost или
localhost.localdomain, проверьте файл
/etc/hosts на машинах с некорректным
выводом. Убедитесь, что реальное имя хоста устройства установлено
перед localhost в строке,
содержащей 127.0.0.1.
I.3.5. Функции запуска #
Плейбук позволяет разделять каталоги
pg_data, pg_wal и
pg_log. Если необходимо разместить
WAL логи в отдельной папке, необходимо внести изменения в
файл inventory/groupvars/patroni.yml:
удалите комментарий для переменной
patroni_pg_wal_dirи укажите каталог для размещения в нем WAL логов;для переменной
patroni_bootstrap_initdbдобавьте параметрwaldirи проверьте, что он ссылается на переменнуюpatroni_pg_wal_dir;для выбранного метода создания реплики (по умолчанию
patroni_pg_basebackup) добавьте параметрwaldirсо значениемbulk_wal_dir;
В случае необходимости размещения LOGов: удалите комментарий для
переменной patron_pg_pg_log_dir и укажите в ней
каталог для размещения журналов LOG;
I.3.6. Запуск плейбука #
Одна из задач плейбука выполняется на том же узле, с которого
запускается ansible (управляющий сервер). Если пользователь, под которым
запускается ansible, не имеет доступа к режиму root без пароля на
этом сервере, необходимо добавить флаг -K к
команде запуска и ввести пароль.
По умолчанию плейбук не пытается подключиться к репозиториям Tantor и требует наличия в системе следующих пакетов:
etcd-tantor-all
python3-tantor-all
patroni-tantor-all
pg_configurator-tantor-all
haproxy-тантор-все
keepalived-tantor-all
pgbouncer-tantor-all
wal-g-tantor-all
СУБД tantor
Обратите внимание на последний пункт из приведенного выше списка. Пакет Tantor должен соответствовать среде, используемой во время запуска плейбука. Например, если вы хотите установить tantor-se-1c-server-16 СУБД с помощью команды ansible-playbook -i inventory/my_inventory -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16" pg-cluster.yaml -K, убедитесь, что пакет tantor-se-1c-server-16 доступен в вашем локальном репозитории.
Если плейбук запускается в среде с доступом в интернет, вы
можете использовать самые актуальные компоненты, включенные в
решение. Для этого добавьте флаг
add_nexus_repo=true и укажите данные для подключения
к репозиториям в файле
inventory/group_vars/prepare_nodes.yml.
Существует несколько вариантов запуска Ansible, с возможностью установки:
Tantor SE-1C
классического PostgreSQL как СУБД.
Используйте следующую команду для установки Tantor SE-1C:
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16" pg-cluster.yaml -K
Используйте следующую команду для установки классической СУБД PostgreSQL:
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=classic major_version=11" pg-cluster.yaml -K
В приведенных выше командах замените значение параметра
major_version на версию СУБД, которую необходимо установить, значение postgresql_vendor
на поставщика СУБД и параметр admin_user
на пользователя, который имеет доступ к серверам без пароля
из файла my_inventory с возможностью
переключения в привилегированный режим (root) без запроса пароля.
Для Tantor SE-1C также необходимо указать редакцию СУБД.
I.3.7. Запуск с доступом в интернет #
Можно запустить плейбук с внешним доступом в интернет.
ansible-playbook -i inventory/my_inventory \ -u admin_user -e "postgresql_vendor=tantordb edition=se-1c major_version=16 add_nexus_repo=true" pg-cluster.yaml -K
В этом случае убедитесь, что детали подключения указаны в
файле
inventory/group_vars/prepare_nodes.yml.
I.3.8. Обслуживание компонентов #
Плейбук поддерживает как полные, так и частичные обновления для большинства компонентов. Каждая роль включает переменную, определяющую требуемую версию компонента (например, переменная pg_configurator_package_version соответствует компоненту pg-configurator-tantor-all). Эти переменные определяются в YAML-файлах inventory/group_vars. При первом запуске будут установлены последние версии компонентов. Если необходимо установить определённую версию, просто задайте соответствующую переменную и запустите плейбук снова.
I.3.9. Примеры использования #
Ниже вы можете найти некоторые общие команды для работы с
программными продуктами, включенными в решение pg_cluster.
Обратите внимание, что команды и их результаты могут отличаться
в зависимости от используемых версий программного обеспечения.
I.3.9.1. Работа с etcd: #
# on NODE_1
e_host=(
/opt/tantor/usr/bin/etcdctl
--endpoints=https://$(hostname -I | awk '{print $1}'):2379
--cacert=/opt/tantor/var/lib/etcd/pg-cluster.pki/ca.pem
--cert=/opt/tantor/var/lib/etcd/pg-cluster.pki/$(hostname).pem
--key=/opt/tantor/var/lib/etcd/pg-cluster.pki/$(hostname)-key.pem
)
# list etcd members
ETCDCTL_API=3 "${e_host[@]}" member list --debug
# check version
ETCDCTL_API=3 "${e_host[@]}" version
# get key value ("main" is "patroni_scope")
ETCDCTL_API=3 "${e_host[@]}" get /service/main/config
# cleanup patroni cluster configuration
ETCDCTL_API=3 "${e_host[@]}" del /service/main --prefix
I.3.9.2. Ручное создание пользователя: #
# create user su - postgres -c "psql -A -t -d postgres -c \"CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'repuserpasswd'\"" # check user su - postgres -c "psql -A -t -d postgres -c \"select * from pg_roles where rolname = 'replicator'\""
I.3.9.3. Управление кластером Patroni #
Patroni включает команду под названием patronictl,
которая может использоваться для управления кластером. Давайте проверим статус
кластера:
root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +---------+-----------------+---------+-----------+----+-----------+
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config
следует использовать только для управления глобальной конфигурацией кластера. Он
не должен содержать никаких настроек, специфичных для узлов, таких как
connect_address, listen,
data_dir и так далее.
Обновить настройки DCS pg_hba:
cat > pg_hba.conf << EOL
host replication replicator 0.0.0.0/0 md5
local all all trust
host all all 127.0.0.1/32 trust
host all all localhost trust
EOL
cat pg_hba.conf | jq -R -s 'split("\n") | .[0:-1] | {"postgresql": {"pg_hba": .}}' | \
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml show-config
Изменить настройки postgresql.conf:
cat > postgresql.conf << EOL
"postgresql": {
"parameters": {
"max_connections" : 101
}
}
EOL
cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml restart main
Сделать переключение switchover:
root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml switchover Current cluster topology + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member| Host | Role | State | TL | Lag in MB | +-------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +-------+-----------------+---------+-----------+----+-----------+ Primary [node1]: Candidate ['node2', 'node3'] []: node2 When should the switchover take place (e.g. 2024-04-02T13:51 ) [now]: Are you sure you want to switchover cluster main, demoting current leader node1? [y/N]: y 2024-04-02 12:51:28.04774 Successfully switched over to "node2" + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member| Host | Role | State | TL | Lag in MB | +-------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | streaming | 2 | | | node2 | yyy.yyy.yyy.yyy | Replica | running | 2 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 2 | 0 | +-------+-----------------+---------+-----------+----+-----------+
Переключиться в асинхронный режим (режим по умолчанию):
cat > postgresql.conf << EOL
"postgresql": {
"parameters": {
"synchronous_commit" : "local"
}
}
"synchronous_mode": false
"synchronous_mode_strict": false
EOL
cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
Переключиться в синхронный режим:
cat > postgresql.conf << EOL
"postgresql": {
"parameters": {
"synchronous_commit" : "remote_apply"
}
}
"synchronous_mode": true
"synchronous_mode_strict": true
EOL
cat postgresql.conf | patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml edit-config --apply - --force main
Диаграмма I.7. synchronous_commit

Повторная инициализация неудавшегося узла, в случае если вывод
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list
предоставляет информацию о неудачном состоянии узла:
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list >> root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+------------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+--------------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | start failed | 1 | 0 | +---------+-----------------+---------+--------------+----+-----------+
Вышедший из строя узел можно перенастроить для присоединения к кластеру с помощью:
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml reinit node3 >> root@node1:~# patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list + Cluster: main (7351350415269982209) --+---------+-----------+----+-----------+ | Member | Host | Role | State | TL | Lag in MB | +---------+-----------------+---------+-----------+----+-----------+ | node1 | xxx.xxx.xxx.xxx | Leader | running | 1 | | | node2 | yyy.yyy.yyy.yyy | Replica | streaming | 1 | 0 | | node3 | zzz.zzz.zzz.zzz | Replica | streaming | 1 | 0 | +---------+-----------------+---------+-----------+----+-----------+
I.3.10. Кластерный тест #
После успешного развертывания кластера:
# on deployment node run test, the test will take about 5 minutes # please use the latest possible version of python3 # please run commands from the pg_cluster folder python3 tools/pg_cluster_backend/pg_cluster_backend.py --operations=10000
Чтобы эмулировать взаимоблокировки, необходимо изменить параметр
test.accounts = 100 -> 10 в
tools/pg_cluster_backend/conf/pg_cluster_backend.conf.
Одновременно с тестированием вы должны выполнить действия с кластером:
# on NODE_1
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml list
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml restart main
shutdown -r now
# on NODE_2
patronictl -c /opt/tantor/etc/patroni/<NODE2_HOSTNAME>.yml list
patronictl -c /opt/tantor/etc/patroni/<NODE2_HOSTNAME>.yml restart main
shutdown -r now
# on NODE_3
patronictl -c /opt/tantor/etc/patroni/<NODE3_HOSTNAME>.yml list
patronictl -c /opt/tantor/etc/patroni/<NODE3_HOSTNAME>.yml restart main
shutdown -r now
# on NODE_1
patronictl -c /opt/tantor/etc/patroni/<NODE1_HOSTNAME>.yml switchover
# on primary node
su - postgres -c "psql -A -t -d test_db -c \"
select pg_terminate_backend(pid)
from pg_stat_activity
where application_name = 'pg_cluster_backend'\""
# on NODE_1
systemctl stop patroni
# on NODE_2
systemctl stop patroni
# on NODE_1
systemctl start patroni
# on NODE_2
systemctl start patroni
# restart all nodes in random order
После выполнения этих действий тестовый сервер должен продолжить работу.
Проверьте, сколько транзакций было потеряно при переключении на асинхронную репликацию:
SELECT
sum(balance)::numeric - -- result balance
((select count(1) from public.accounts) * 100 + 10000) -- where "--operations=10000"
FROM public.accounts
-- positive value means lost transactions
-- negative value means successfully committed transactions in which the backend received an exception
