В статье описывается один из способов обновления дистибутива операционной системы с работающим кластером баз данных Postgres Pro Standard версии 11. В дальнейшем, для краткости, кластер баз данных Postgres Pro Standard 11 будем называть Postgrespro, Centos7 - Centos, а AlmaLinux8 - Almalinux. Способ заключается в том, чтобы настроить физическую репликацию Postgrespro между разными дистрибутивами операционной системы с последующим переводом слейва в режим мастера. При чтении множества статей о настройке физической репликации я нигде не встречал упоминание о том, что так делать нельзя. Естественно, что архитектура Centos и Almalinux должны совпадать, а так же должны совпадать мажорные версии Postgrespro.
Немного о том, что за Postgrespro переносим
провайдер сортировки ICU
размер всех баз составляет 100G
в среднем 3000 транзакций в секунду при 21 коннекте
для коннектов используется pgbouncer в режиме session (pool_mode = session)
Исходные данные
Postgrespro на сервере с Centos - рабочая база
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 11.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-28), 64-bit
Postgrespro на сервере с Almalinux - чистая установка
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 11.18 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.3.1 20191121 (Red Hat 8.3.1-5), 64-bit
Краткая последовательность действий
Настраиваем физическую репликацию между Postgrespro на Centos (мастер) и Almalinux (слейв).
Стопаем клиентские коннекты в pgbouncer.
Переводим слейв в режим мастера.
Переключаем клиентские коннекты в pgbouncer на новый мастер.
На новом мастере в каждой базе обновляем версию правил сортировки.
Описание действий
Не буду описывать как настроить физическую репликацию, т.к. в интернете много инструкций. Скажу лишь, что у нас настроена потоковая репликация + архивирование wal файлов.
У pgbouncer есть замечательная команда PAUSE
для приостановки клиентских коннектов. Но она не совсем подходит (я бы сказал, что совсем не подходит) для базы с постоянными соединениями, т.к. она не отработает до тех пор, пока все активные клиентские коннекты не отключатся. Например, если открыть psql, подлючиться к базе, выполнить любой запрос и оставить psql подключенной к базе, затем (в другом терминале) подлючиться к pgbouncer и выполнить PAUSE
, то она замрет в ожидании закрытия psql. В то время как PAUSE
будет ждать закрытие соединения psql, новые клиенты не смогут подключаться к базе. Проблема PAUSE
еще и в том, что пока она "виснет", сделать на базу KILL
так же не выйдет, будет ошибка ERROR: already suspended/paused
, т.е. PAUSE
вообще никак не прервать - только перезапуск pgbouncer. Поэтому, мы решили стопать клиентские коннекты через KILL
, как итог, получили пару седых волос, но об этом позже.
После останова клиентских коннектов ждем пару секунд (чтобы слейв догнал мастер)
и переводим слейв в режим мастера. Способов несколько, мы это делаем через создание триггерного файла. Кто-то скажет, что подождать пару секунд так себе вариант чтобы убедиться в том, что слейв догнал мастер, тогда можно выполнить запрос к pg_stat_replication на текущем мастере и убедится, что sent_lsn, write_lsn, flush_lsn, replay_lsn равны.
После того, как новый мастер готов принимать соединения, в конфиге pgbouncer меняем строки коннекта к текущим базам на новый мастер и в подключении к pgbouncer возобновляем клиентские коннекты командой RESUME.
Поскольку в дистрибутивах Centos и Almalinux разные версии библиотеки ICU, а Postgrespro отслеживает изменение версий ICU в системе, то на новом мастере при каждом коннекте к базе, показывается такое предупреждение:
WARNING: collation "default" has version mismatch
DETAIL: The collation in the database was created using version 58.0.6.50, but the operating system provides version 153.80.
HINT: Check all objects affected by this collation and run ALTER COLLATION pg_catalog."default" REFRESH VERSION
Чтобы избавиться от этого предупреждения, мы написали простенький скрипт на perl, который нужно запустить на новом мастере:
#!/usr/bin/env perl
# https://postgrespro.ru/docs/postgrespro/11/sql-altercollation#SQL-ALTERCOLLATION-NOTES
# Обновляет версии провайдера сортировки ICU во всех базах.
# Запускать на всех базах кластера, кроме template0 (т.к. к ней нельзя подконнектится).
# Запускать от пользователя postgres
use strict;
use warnings;
use DBI;
my @dbs = qw/analytics log postgres template1 testdb/;
# https://edu.postgrespro.ru/dba2-13/dba2_16_admin_localization.html
my $sql = qq/
SELECT
c.collname,
c.collversion AS version,
pg_collation_actual_version(c.oid) AS actual_version
FROM
pg_collation c
WHERE
pg_collation_actual_version(c.oid) IS NOT NULL
/;
for my $dbname (@dbs) {
print "------- $dbname -------\n";
my $dbh = DBI->connect("dbi:Pg:dbname=$dbname", "", "", { RaiseError=>1});
my $arr = $dbh->selectall_arrayref($sql, { Slice => {} });
for (@$arr) {
if ($_->{version} ne $_->{actual_version}) {
print "$_->{collname}: $_->{version} to $_->{actual_version}\n";
$dbh->do('ALTER COLLATION pg_catalog."'.$_->{collname}.'" REFRESH VERSION');
}
}
}
Хочу заметить, что у нас в Postgrespro сортировка у всех баз одинаковая en_US.UTF-8@icu
и в базах не используется сортировка отличная от default. Если у Вас иначе, то читать до понимания происходящего эту и эту ссылки.
Вот казалось бы и все, задача решена, дистрибутив операционной системы заменен, новый мастер держит нагрузку, ошибок нет. Помните, ранее, я говрил о седых волосах, так вот спустя пару минут работы на новом мастере мы заметили, что порядковый номер заказов прыгнул на 31, т.е. последовательность (первичный ключ) в таблице orders была 1004304, а на новом мастере вдруг стала 1004335. Мы не поверили своим глазам, как так то, ведь перед тем, как мы перевели слейв в режим мастера мы убедились, что sent_lsn, write_lsn, flush_lsn, replay_lsn равны, т.е. мастер и слейв были в одинаковых состояниях. Взглянув на другие посследовательности на новом мастере мы обнаружили, что такой скачок произошел и в других последовательностях. Немного подумав, мы поняли, что на самом деле ничего старшного в этом нет, ну прыгнули они и прыгнули, нас напугал сам факт того, что такой скачок произошел. А может тогда еще что-то где-то сломалось? Ведь мы использовали разные версии дистрибутивов операционной системы. Если коротко, то найти ответ на вопрос о скачке последовательностей нам помог второй слейв, да у нас был второй слейв, который застыл в сотоянии когда мы отрубили коннекты от старого мастера. И вот что показал запрос на втором слейве:
# SELECT * FROM orders_id_seq;
last_value | log_cnt | is_called
------------+---------+-----------
1004304 | 31 | t
(1 row)
Вся фишка в log_cnt, погуглив мы тут же наткнулись на ответ. Если коротко, то да, скачок последовательностей возможен. Прикиньте!
Выводы
Простой в работе занял ровно минуту.
Скачок последовательностей произошел из-за того, что мы остановили клиентские коннекты на pgbouncer через команду
KILL
.Возможно (не проверяли), проблема команды
PAUSE
описанная в этой статье возникает только в режиме session, а в режиме transaction нет.