Многие в настоящее время сталкиваются с необходимостью миграции с AstraLinux 1.7 на AstraLinux 1.8.
Для тех, кто пользуется штатной PostgreSQL 11 из поставки AstraLinux 1.7, встает во весь рост вопрос, как перетащить существующие базы на новую версию. Если базы маленькие, особых проблем нет. А вот если базу под 1ТБ, то проблемы встают в полный рост.
Для штатной pg_upgrade требуются обе версии (PostgreSQL-11 и PostgreSQL-15). Но в поставке AstraLinux 1.8 нет PostgreSQL 11. При этом, так как Astra PostgreSQL не совместим бинарно с "Ванилью", то и не получится собрать самому нужную версию для Astra 1.8.
"Вкорячить" его из поставки Astra 1.7 можно, но разница NAMEDATALEN между версиями ставит крест на использование pg_upgrade (Смотрите засаду 1).
Штатный pg_dump | pg_restore в одну нитку, для базы 1.1 Тб у нас на стенде работал аж 27 часов. Максимальный размер технологического окна при этом установлен 24 часа.
Может быть еще одна причина для выбора pg_dump/pg_restore варианта - если datafile исходной базы и целевой базы бинарно несовместимы. Как например несовместимы между собой datafiles наиболее часто использующихся дистрибутивов PostgreSQL:
"Ваниль"
PostgresPro EE/SE
Tantor
Штатная PostgreSQL 11 AstraLinux 1.7
Штатная PostgreSQL 15 AstraLinux 1.8
Поиск решения (помимо логической репликации), навел на утилиту pgcopydb
Для начала засады:
1) в Astra1.8 в PostgreSQL уменьшили длину типа name с 255 байт до 63.
https://docs.astralinux.ru/latest/guide/application/devfeature/
Не поддерживаются длинные имена идентификаторов
При использовании длинных идентификаторов (имен) возникают ошибки. Максимальная длина идентификатора составляет:
при использовании символов ASCII (в частности, латиницы) — 63 символа;
при использовании кириллицы (кодировка utf8) — 31 символ;
при использовании других символов максимальная длина идентификатора уменьшается и зависит от использованного набора символов.
Рекомендации
Максимальная допустимая длина идентификатора задается при сборке и не может быть изменена.
В Astra Linux Special Edition x.7 использовалась максимальная длина идентификатора 255 байт (сборка ЗСУБД с параметром NAMEDATALEN = 256).
В Astra Linux Special Edition x.8 в целях оптимизации производительности, улучшения тестирования и повышения устойчивости работы ЗСУБД максимальная длина идентификатора уменьшена до 63 байт (NAMEDATALEN=64).
Прикладное ПО должно быть адаптировано к этим изменениям.
Поэтому, при использовании длинных идентификаторов (имен) возникают ошибки при pg_dump15/pg_restore15 при работе с PostgreSQL-11. При этом утилиты pg11 без проблем работают с PostgreSQL-15.
Из-за этого, для миграции с использованием pgcopydb его нужно собирать именно на astra1.7.
При тестировании наткнулся на еще одну проблему в связи с эти "улучшением":
Попытка
> pg_upgrade -m clone 11 main ...
> старая и новая максимальная длина идентификаторов в pg_controldata различаются или
> некорректны
> Ошибка, выполняется выход
Увы, pg_upgrade не сработает для набора этих версий.
2) pgcopydb не понимает MAC LABEL SECURITY
3) PG12+: больше не поддерживается созданием таблиц с кляузой "WITH OIDS"
Ранее в таблицу можно было добавить столбец oid (невидимый в обычных запросах), создавая её с указанием WITH OIDS; теперь такой возможности нет. При этом по-прежнему возможно создавать столбцы с типом oid. С учётом этого изменения порядок использования таблиц, созданных с указанием WITH OIDS, потребуется скорректировать.
Системные каталоги, в которых были скрытые столбцы oid, теперь содержат обычные столбцы oid. Таким образом, эти столбцы будут выводиться в результате запроса SELECT *, тогда как ранее они выводились только в случае явного указания.
Сборка pgcopydb
Сборку рекомендуется выполнять на отдельной машине, так как средства разработки не допускаются в закрытом контуре.
apt-get install -y --no-install-recommends \
git \
build-essential \
autotools-dev \
libedit-dev \
libgc-dev \
libpam0g-dev \
libreadline-dev \
libselinux1-dev \
libxslt1-dev \
libssl-dev \
libkrb5-dev \
zlib1g-dev \
liblz4-dev \
libpq5 \
libpq-dev \
libzstd-dev \
postgresql-server-dev-all \
postgresql-common \
postgresql \
python3-sphinx
git clone https://github.com/dimitri/pgcopydb
cd pgcopydb
make
Инсталляция pgcopydb на другую машину
Для инсталляции нужен только сам исполняемый файл pgcopydb и библиотека libgc.so.1
## Скопировать полученный файл на нужную машину
scp src/bin/pgcopydb/pgcopydb targethost:bin/
## разрешить установку права запуска для файлов
sudo astra-nochmodx-lock disable
## добавляем возможность запуска
chmod 0755 pgcopydb
## доставить библиотеку libgc.so.1
apt install libgc1c2
Так, как pgcopydb не понимает MAC LABEL SECURITY, ставим обертку для pg_dump, pg_restore, pg_dumpall
cd /usr/lib/postgresql/11/bin
mv pg_dump pg_dump.bin
mv pg_dumpall pg_dumpall.bin
mv pg_restore pg_restore.bin
## добавляем опции отключающие MAC LABEL
echo "/usr/lib/postgresql/11/bin/pg_dump.bin --no-security-labels --disable-macs $@" > pg_dump
echo "/usr/lib/postgresql/11/bin/pg_dumpbin.bin --no-security-labels $@" > pg_dumpall
echo "/usr/lib/postgresql/11/bin/pg_restore.bin --no-security-labels $@" > pg_restore
chmod 0755 pg_dump pg_dumpall pg_restore
Подготовка исходной базы
Правим длинные имена
получить список объектов для поля типа name > 63 bytes
Для этого тупо генерируем запросы select ... from object where length(name) > 63 для всех объектов где есть поле name, и выполняем полученный tmp.sql в отдельном шаге.
Готовим файл запроса полей name и формирования запросов к каждой такой таблице (файл q1.sql):
select
'SELECT '''||table_schema||'.'||table_name||'.'||column_name||': ''||'|| column_name ||
' FROM "'||table_schema||'"."'||table_name||'" WHERE '||'length("'||column_name||'") > 63;'
from information_schema.columns
where
data_type = 'name'
;
Выполняем следующую команду:
## для каждой базы, формируем tmp.sql и потом выполняем его для получения списка объектов
psql -AXtc "select datname from pg_database"|while read db
do echo "==== $db =====";
psql -AXt -d $db -f q1.sql > tmp.sql
psql -d $db -AtX -f tmp.sql > $db.txt
done
Передаем полученный список разработчикам, чтобы убрали длинные имена.
Правим "WITH OIDS" у таблиц
Получаем команды для правки таблиц
-- генерация команд для правки таблиц
SELECT 'ALTER TABLE "' || n.nspname || '"."' || c.relname || '" SET WITHOUT OIDS;'
FROM pg_catalog.pg_class c
LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace
WHERE 1=1
AND c.relkind = 'r'
AND c.relhasoids = true
AND n.nspname <> 'pg_catalog'
order by n.nspname, c.relname;
-- выполняем полученные команды, например
test=# ALTER TABLE "abc"."recipients_m11" SET WITHOUT OIDS;
ALTER TABLE
test=# ALTER TABLE "abc"."config_m11" SET WITHOUT OIDS;
ALTER TABLE
test=# ALTER TABLE "abc"."data_m11" SET WITHOUT OIDS;
Подготовка целевой базы
Тут все просто, шаги те же что и для обычного pg_dump/pg_restore
например:
создаем базу с нужным owner
переносим роли и extension
# first two commands would use a superuser role
$ pgcopydb copy roles --source ... --target ...
$ pgcopydb copy extensions --source ... --target ...
Можно запускать pgcopydb для миграции
export PGCOPYDB_SOURCE_PGURI="postgres://user@source.host.dev/dbname"
export PGCOPYDB_TARGET_PGURI="postgres://role@target.host.dev/dbname"
pgcopydb clone --table-jobs 4 --index-jobs 4