Обычно, когда речь заходит про миграцию базы данных, задача формулируется так: без простоя и с минимальными усилиями перенести базу в облако. Процесс кажется понятным, однако на практике приходится учитывать множество нюансов.
Предварительные условия
Первый шаг — установка сетевой связности между выделенным сервером и кластером базы данных в облаке. Мы не будем останавливаться на возможных схемах взаимодействия с БД, создании и настройки кластера, организации сетевой связности между компонентами системы. Это обширная тема, которая не касается напрямую предмета сегодняшнего рассмотрения — миграции БД.
В статье «Способы организации инфраструктуры с базами данных: от простого к сложному» все необходимые действия подробно описаны, в том числе настройка интерфейса выделенного сервера и проверка подключения.
Будем считать, что кластер БД в облаке создан, настроен, а соединение работает. Наша база данных на выделенном сервере, которую будем использовать в качестве демонстрационного примера, содержит единственную таблицу с несколькими записями. СУБД — PostgreSQL 13-й версии. Миграцию будем осуществлять с помощью логической репликации, когда все изменения происходят в результате выполнения SQL‑запросов или соответствующих методов API.
Для наших примеров возьмем следующие адреса:
192.168.14.2/24
— для выделенного сервера;
10.10.14.2/24
— для облачной базы данных.
Подготовка БД
Выделенный сервер
Подготовим СУБД на выделенном сервере для логической репликации. Для этого внесем несколько изменений в конфигурационный файл PostgreSQL /etc/postgresql/13/main/postgresql.conf
(его расположение может варьироваться в зависимости от параметров установки СУБД).
1. Параметр wal_level
(Write-Ahead Log) определяет сколько информации заносится в журнал предзаписи. Значение по умолчанию minimal ограничивает запись лишь информацией, которая необходима для восстановления после сбоя или аварийного отключения. Будем использовать logical
для поддержки логической репликации.
wal_level = logical
2. Выполним подключение к подсети в рамках глобального роутера, о настройке которого мы рассказывали в отдельной статье:
listen_adresses = '192.168.14.2'
3. Настроим аутентификацию, чтобы далее смогли выполнить репликацию. Для этого внесем изменения в файл /etc/postgresql/13/main/pg_hba.conf
.
4. Обязательно необходим доступ из подсети облака к кластеру на выделенном сервере:
# TYPE DATABASE USER ADDRESS METHOD
...
host all all 10.10.14.0/24 md5
...
5. Для доступа репликации из подсети облака:
# TYPE DATABASE USER ADDRESS METHOD
...
host replication all 10.10.14.0/24 md5
...
Условно обозначим кластер на выделенном сервере «источником», а кластер в облаке — «приемником».
6. Перезапустим сервис PostgreSQL, чтобы изменения вступили в силу:
systemctl restart postgresql
Облачная база данных
1. В панели управления проверим состояние кластера‑приемника в облаке. Перейдем в раздел Облачная платформа → Базы данных:
2. Выберем наш кластер‑приемник. Создадим пользователя и базу данных, которые будем использовать для миграции.
В листингах Unix Shell представленных ниже, ввод команд перемежается с выводом. Условимся считать, что в начале строк:
$ — приглашение Shell;
= > — приглашение СУБД;
^ — нажатие клавиши Ctrl (Cmd на Маках).
4. Убедимся в доступности кластера‑приемника со стороны выделенного сервера. Для этого пошлем проверочные эхо‑пакеты:
$ ping master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru
PING 76439e43-8be7-46d9-b059-d5579081e878.ru-7.c.dbaas.selcloud.ru (10.10.14.103) 56(84) bytes of data.
64 bytes from 10.10.14.103 (10.10.14.103): icmp_seq=1 ttl=62 time=35.5 ms
64 bytes from 10.10.14.103 (10.10.14.103): icmp_seq=1 ttl=62 time=9.80 ms
^С
5. Связность установилась. Подключаемся к нашему кластеру в облаке:
$ psql -U myuser -h master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru mydb
Password for user myuser:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1), server 14.7 (Ubuntu 14.7-1.pgdg18.04+1ubuntu1))
WARNING: psql major version 13, server major version 14.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compresion: off)
Type "help" for help.
mydb = > \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access priviliges
---------+----------+----------+---------+-------+------------------
mydb | myuser | UTF8 | C | C | myuser=CTc/myuser
...
(4 rows)
mydb = >
Важно убедиться, что база данных, которую мы создали в панели управления, отображается в списке.
Для полноты примера мы взяли ситуацию, когда в облаке и на выделенном сервере мажорные версии PostgreSQL отличаются. Если версии psql будут одинаковые, то предупреждения о потенциальной неработоспособности некоторых возможностей не появится.
Перенос схемы
До начала переноса данных нужно перенести схему БД. Удобнее всего сделать это с помощью утилиты pg_dump
.
Схема базы данных — её структура, описанная на формальном языке, которая описывает таблицы, поля (название, тип, обязательность), ключи, различные ограничения.
Обратите внимание: копируется только схема, без привилегий.
1. Укажем корректные значения хоста, порта, названия БД, а также имени пользователя и произведем выгрузку:
$ pg_dump "host=127.0.0.1 port=5432 dbname=demo user=user1" --schema-only --no-privileges --no-subscriptions --no-publications -Fd -f dump
2. Перенесем скопированную схему в кластер облачной БД. При этом так же не воспроизводим привилегии на объекты. Оптимально для точки входа в кластер использовать DNS‑имя лидера — активного узла, который принимает решения и координирует действия. В таком случае, если кластер состоит из нескольких узлов, мы гарантированно получим доступ именно к управляющему узлу. Базу данных указываем ту, в которую переносим схему.
$ pg_restore -Fd -v --single-transacrion -s --no-privileges -O -h master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru -U myuser -p 5432 -d mydb dump
pg_restore: connection to database for restore
Password:
pg_restore: creating TABLE "public.movies"
pg_restore: creating CONSTRAINT "public.movies movies_pkey"
В облачной базе данных появилась новая пустая таблица:
$ psql -U myuser -h master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru mydb
Password for user myuser:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1), server 14.7 (Ubuntu 14.7-1.pgdg18.04+1ubuntu1))
WARNING: psql major version 13, server major version 14.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compresion: off)
Type "help" for help.
mydb = > \dt
List of relations
Schema | Name | Type | Owner
-------+--------+-------+--------
public | movies | table | myuser
mydb = >
Перенос данных
Последующие действия выполняем на выделенном сервере, на котором и находятся пока все данные:
$ psql -U user1 -h 192.168.14.2 demo
Password for user user1:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
demo = > SELECT * FROM movies ;
movie_id | title | genres
---------+----------------+-----------------------------
1 | Tarsan | Animation|Adventure|Drama
2 | The Lake House | Romance|Drama
3 | Blood Diamond | Adventure|Thriller
4 | The Pianist | Drama
(4 rows)
demo = >
В нашей демонстрационной таблице есть четыре записи.
Далее необходимо создать публикацию на стороне выделенного сервера.
Публикация — набор изменений в группе таблиц, который определяется на ведущем сервере репликации. Такой сервер называется публикующим. В отличие от схем, публикации не влияют на доступ к таблицам.
1. Название публикации задаем произвольное, в примере ниже — pub
.
$ sudo -u postgres psql
could not change directory to "/root": Permission denied
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1))
Type "help" for help.
postgres=# ALTER ROLE user1 WITH superuser;
ALTER ROLE
postgres=#
\q
$ psql -U user1 -h 192.168.14.2 demo
Password for user user1:
psql (13.11 (Ubuntu 13:11-m.pgdg22.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
demo=# CREATE PUBLICATION pub FOR ALL TABLES;
CREATE PUBLICATION
demo=#
Для создания публикации для всех таблиц понадобятся права суперпользователя.
В случае, когда пользователь является владельцем базы без привилегий суперпользователя, он также может создать пустую публикацию, добавляя каждую таблицу отдельно.
$ psql -U user1 -h 192.168.14.2 demo
Password for user user1:
psql (13.11 (Ubuntu 13:11-m.pgdg22.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
demo=# CREATE PUBLICATION pub;
CREATE PUBLICATION
demo=# ALTER PUBLICATION pub ADD TABLE movies;
ALTER PUBLICATION
2. На стороне облачной базы данных создадим подписку. Название для нее выберем произвольное, в используемом примере — sub
. Кроме того, укажем параметры подключения к выделенному серверу, а также данные учетной записи пользователя. Обратите внимание, номер порта — тот, на котором работает СУБД PostgreSQL.
$ psql -U myuser -h master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru mydb
Password for user myuser:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1), server 14.7 (Ubuntu 14.7-1.pgdg18.04+1ubuntu1))
WARNING: psql major version 13, server major version 14.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
mydb = > CREATE SUBSCRIPTION sub CONNECTION 'host=192.168.14.2 port=5432 dbname=demo user=user1 password=mypassword' PUBLICATION pub;
NOTICE: created replication slot "sub" on publisher
CREATE SUBSCRIPTION
mydb = > SELECT * FROM pg_subscription_rel;
srsubid | srrelid | srsubstate | srsublsn
---------+---------+------------+-----------
16410 | 16402 | r | 0/15F42A8
(1 row)
mydb = > SELECT * FROM movies ;
movie_id | title | genres
---------+----------------+-----------------------------
1 | Tarsan | Animation|Adventure|Drama
2 | The Lake House | Romance|Drama
3 | Blood Diamond | Adventure|Thriller
4 | The Pianist | Drama
(4 rows)
mydb = >
Флаг r
в столбце srsubstate
говорит о том, что подписка готова принимать данные. Видим, что таблица в облачной БД наполнилась строками из таблицы на выделенном сервере.
Чтобы создавать подписки на стороне кластера облачных баз данных, пользователь должен обладать привилегией dbaas_admin
.
Все владельцы БД автоматически получают такую привилегию без запроса.
Проверка синхронизации
Убедимся, что базы данных на выделенном сервере и в облаке обмениваются информацией и синхронизируют свое содержимое.
1. Внесем небольшие изменения со стороны выделенного сервера. Пусть жанр для The Pianist
вместо Drama
станет Drama|Music
.
$ psql -U user1 -h 192.168.14.2 demo
Password for user user1:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compression: off)
Type "help" for help.
demo=# UPDATE movies SET genres = 'Drama|Music' WHERE movie_id = 4;
UPDATE 1
demo = > SELECT * FROM movies ;
movie_id | title | genres
---------+----------------+-----------------------------
1 | Tarsan | Animation|Adventure|Drama
2 | The Lake House | Romance|Drama
3 | Blood Diamond | Adventure|Thriller
4 | The Pianist | Drama|Music
(4 rows)
demo = >
2. Посмотрим, изменились ли данные в облачной базе данных:
$ psql -U myuser -h master.c3241135-79a6-46c2-afa6-d49035e83b13.c.dbaas.selcloud.ru mydb
Password for user myuser:
psql (13.11 (Ubuntu 13.11-1.pgdg22.04+1), server 14.7 (Ubuntu 14.7-1.pgdg18.04+1ubuntu1))
WARNING: psql major version 13, server major version 14.
Some psql features might not work.
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, bits: 256, compresion: off)
Type "help" for help.
mydb = > SELECT * FROM movies ;
movie_id | title | genres
---------+----------------+-----------------------------
1 | Tarsan | Animation|Adventure|Drama
2 | The Lake House | Romance|Drama
3 | Blood Diamond | Adventure|Thriller
4 | The Pianist | Drama|Music
(4 rows)
mydb = > DROP SUBSCRIPTION sub;
NOTICE: dropped replication slot "sub" on publisher
DROP SUBSCRIPTION
mydb = >
Действительно, поле genres для записи с movie_id=4
также сменилось с Drama
на Drama|Music
.
Стоит отметить, что последовательности не реплицируются — их надо переносить отдельно, например, с использованием pg_dump
.
В завершение удаляем ненужную более подписку и переносим нагрузку на приемник.
Аналогично производится репликация между облачный базой данных и каким‑либо внешним сервером. Главное — предварительная настройка сетевой связности. Со стороны облачной БД пользователь должен обладать привилегиями dbaas_replication
и SELECT
на все объекты, которые будут реплицированы.
Заключение
Мы рассмотрели как подготовить БД, как перенести сначала схему, затем данные. Убедились, что работает синхронизация. Это не всегда необходимо делать самостоятельно, крупные облачные провайдеры обычно предоставляют услугу миграции базы данных. Специфика DBaaS не ограничивается простым размещением таблиц в облаке. Можно настроить разделение доступов с помощью IAM‑системы, добавить реплик для отказоустойчивости кластера, подключить систему мониторинга и многое другое. Обо всех специфических возможностях можно узнать на странице нашего сервиса.