Миграция трекера MogileFS с MySQL на PostgreSQL
Содержание
Вступление
Имеется большое количество серверов баз данных, настроенных разными людьми и под разные задачи. Поскольку многие серверы по-сути друг друга дублируют, то было бы неплохо перенести базы данных так, чтобы вывести из эксплуатации часть серверов.
В рамках этой затеи задумал перенести базы данных трекеров MogileFS с виртуальной машины с Percona Server 5.7 на кластер виртуальных машин Percona XtraDB Cluster 5.7. Однако после переноса базы данных и переключения трекеров на использвание новой базы данных в журнале ошибок /var/log/mysql/error.log на Percona XtraDB Cluster стали появляться ошибки следующего вида:
[ERROR] WSREP: Percona-XtraDB-Cluster prohibits use of GET_LOCK with pxc_strict_mode = ENFORCING
Оказалось, что трекер MogileFS использует функции GET_LOCK
и RELEASE_LOCK
, которые Percona XtraDB Cluster не поддерживает.
Функции GET_LOCK
и RELEASE_LOCK
используются в модуле MogileFS::Store::MySQL
. Самая свежая версия этого модуля, доступная в репозитории, также использует эти функции. В этом можно убедиться, заглянув на страницу по ссылке https://github.com/mogilefs/MogileFS-Server/blob/master/lib/MogileFS/Store/MySQL.pm
Поскольку кроме модуля MogileFS::Store::MySQL
я нашёл также модули MogileFS::Store::Postgres
и MogileFS::Store::SQLite
, то решил попробовать перенести данные из имеющейся базы данных на сервер баз данных под управлением PostgreSQL. SQLite не подходит хотя бы по той простой причине, что есть несколько трекеров, работающих с общей для них базой данных.
В прошлом у меня уже был успешный опыт использоавния инструмента pgloader
для переноса данных из MySQL в PostgreSQL, поэтому я решил воспользоваться им. Но прежде чем переносить сами данные, мне нужна структура таблиц базы данных, которая используется трекером для хранения своих данных в PostgreSQL.
Структура базы данных
Получим исходные тексты из репозитория (я использовал для этого свой компьютер):
$ git clone https://github.com/mogilefs/MogileFS-Server
Последней версией сервера MogileFS является версия 2.72, но в моём случае используется версия 2.70. Переключимся на нужную нам версию воизбежание дальнейших проблем со структурой базы данных:
$ git checkout 2.70
Для получения структуры базы данных нам потребуется утилита mogdbsetup
. MogileFS написан на Perl, а для работы утилиты понадобится доустановить в систему некоторые дополнительные пакеты:
# apt-get install libdbi-perl libdanga-socket-perl libdbd-pg-perl libnet-netmask-perl
Создадим пользователя и базу данных:
# su - postgres
$ createuser -P mogilefs
$ createdb -O mogilefs -E UTF-8 mogilefs
$ exit
Теперь воспользуемся утилитой mogdbsetup и создадим в базе данных таблицы и последовательности для MogileFS:
$ ./mogdbsetup --yes --type=Postgres --dbname=mogilefs --dbuser=mogilefs --dbpass=deeva7Er
Сохраняем структуру базы данных без самих данных:
$ pg_dump -s -U mogilefs -W -d mogilefs > mogilefs_schema.sql
Структура базы данных у нас есть. Теперь можно удалить исходные тексты MogileFS и установленные для неё дополнительные пакеты, если они больше ничем не используются, например, вот так:
$ rm -R MogileFS-Server
И вот так:
# apt-get remove libdbi-perl libdanga-socket-perl libdbd-pg-perl libnet-netmask-perl
# apt-get autoremove
Перенос данных
Первым делом установим пакет pgloader
:
# apt-get instal pgloader
Теперь создадим файл конфигурации migrate_mogilefs.load
для переноса данных, в который поместим следующее содержимое:
LOAD DATABASE
FROM mysql://mysql_user:mysql_password@mysql.domain.tld:3306/mysql_db
INTO postgresql://postgres_user:postgres_passwor@postgres.domain.tld:5432/postgres_db
ALTER SCHEMA 'mysql_db' RENAME TO 'public'
WITH include no drop,
truncate,
create no tables,
create no indexes,
no foreign keys,
reset sequences,
data only
SET PostgreSQL PARAMETERS
maintenance_work_mem to '128MB',
work_mem to '12MB',
search_path to 'postgres_db, public, "$user"'
BEFORE LOAD EXECUTE mogilefs_schema.sql
AFTER LOAD EXECUTE mogilefs_seq.sql;
В этом файле конфигруации используются следующие настройки для подключения к исходной базе данных MySQL и для целевой базе данных PostgreSQL:
mysql_user
- пользователь, имеющий права на чтение содержимого базы данных на сервере MySQL,mysql_password
- пароль пользователя на сервере MySQL,mysql.domain.tld
- доменное имя сервера MySQL (можно использовать и IP-адрес),mysql_db
- имя базы данных в MySQL,postgres_user
- пользователь, имеющий права как минимум на вставку строк в таблицы базы данных на сервере PostgreSQL,postgres_password
- пароль пользователя на сервере PostgreSQL,postgres.domain.tld
- доменное имя сервера PostgreSQL (можно использовать и IP-адрес),postgres_db
- имя базы данных в PostgreSQL.
Кроме этого, если вы используете нестандартные порты на сервере MySQL или на сервере PostgreSQL, не забудьте поменять номера портов 3306 и 5432 на используемые вами.
По сравнению с моими прошлыми статьями, в которых был описан перенос данных между MySQL и PostgreSQL на примере баз данных Zabbix и Redmine, в этой статье в файле конфигурации появилось одно важное выражение:
ALTER SCHEMA 'mysql_db' RENAME TO 'public'
Дело в том, что в pgloader
, начиная с версии 3.4, происходит попытка импортировать данные в таблицы PostgreSQL, находящиеся в схеме, имя которой совпадает с именем базы данных в MySQL. Указанное выше выражение нужно для того, чтобы в процессе импорта использовались таблицы из схемы public.
Перед переносом данных выполняются SQL-запросы из файла mogilefs_schema.sql
.
Получненный до этого файл mogilefs_schema.sql
нужно доработать следующим образом:
- Удалить комментарии и пустые строки, т.к.
pgloader
ожидает, что в каждой строчке будет указан какой-то запрос, который что-то изменяет, - Удалить двойные кавычки вокруг имён полей, совпадающих с зарезервированными словами,
- Сменить владельца базы данных, если владелец реальной базы данных отличается от владельца тестовой базы данных, с помощью которой был получен файл
mogilefs_schema.sql
.
Сделать это можно вот так:
$ cat mogilefs_scheme.sql | sed -e 's/^--.*$//g; /^$/d; s/"//g; s/TO mogilefs/TO mogilefs_12/g' > mogilefs_scheme.new
$ mv mogilefs_scheme.new mogilefs_scheme.sql
Поскольку перед окончательным переносом базы данных я делал тестовые прогоны, то я также добавил в начало файла mogilefs_scheme.sql
запрос, удаляющий все таблицы, которые будут создаваться скриптом:
DROP TABLE IF EXISTS public.checksum,
public.class,
public.device,
public.domain,
public.file,
public.file_on,
public.file_on_corrupt,
public.file_to_delete,
public.file_to_delete2,
public.file_to_delete_later,
public.file_to_queue,
public.file_to_replicate,
public.fsck_log,
public.host,
public.lock,
public.server_settings,
public.tempfile,
public.unreachable_fids;
Получившийся файл, соответствующий MogileFS версии 2.70, можно взять по ссылке mogilefs schema.sql.
После перноса данных выполняются SQL-запросы из файла mogilefs_seq.sql
, в который я поместил запросы для обновления текущих значений двух последовательностей, используемых для назначения идентификаторов записей в таблицах:
SELECT SETVAL('fsck_log_logid_seq', (SELECT MAX(logid)
FROM fsck_log));
SELECT SETVAL('tempfile_fid_seq', (SELECT MAX(fid)
FROM (
SELECT MAX(fid) AS fid
FROM tempfile
UNION SELECT MAX(fid)
FROM checksum
UNION SELECT MAX(fid)
FROM file
UNION SELECT MAX(fid)
FROM file_on
UNION SELECT MAX(fid)
FROM file_on_corrupt
UNION SELECT MAX(fid)
FROM file_to_delete
UNION SELECT MAX(fid)
FROM file_to_delete2
UNION SELECT MAX(fid)
FROM file_to_delete_later
UNION SELECT MAX(fid)
FROM file_to_queue
UNION SELECT MAX(fid)
FROM file_to_replicate
UNION SELECT MAX(fid)
FROM fsck_log
UNION SELECT MAX(fid)
FROM tempfile
UNION SELECT MAX(fid)
FROM unreachable_fids
) AS t
)
);
Эти запросы находят максимальное значение каждого из идентификаторов среди уже существующих в таблицах записей и присваивают эти значения последовательностям.
Для запуска переноса данных остаётся запустить сам pgloader
:
$ pgloader migrate_mogilefs.load
После завершения переноса данных программа выведет отчёт о проделанной работе. Стоит убедиться, что в колонке errors фигурируют только нули. Это будет означать, что перенос данных завершился успешно.
Переключение трекера
Для переключения трекера на использование новой базы данных необходимо доустановить в систему модуль DBD::Pg
:
# apt-get install libdbd-pg-perl
И заменить в файле конфигурации /etc/mogilefs/mogilefsd.conf
настройки подключения к базе данных и, при необходимости, логин и пароль:
db_dsn = DBI:Pg:dbname=postgres_db;host=postgres.domain.tld;port=5432;connect_timeout=5
db_user = postgres_user
db_pass = postgres_password
Перед переключением можно проверить наличие возможности подключения с помощью простого скрипта на Perl:
#!/usr/bin/perl
use warnings;
use strict;
use DBI;
my $dh = DBI->connect(
"DBI:Pg:dbname=postgres_db;host=postgres.domain.tld;port=5432;connect_timeout=5",
"postgres_user",
"postgres_password",
{
RaiseError => 0,
PrintError => 0
}
);
if (defined $dh) {
print "Connection successful.\n";
} else {
print "Connection failed!\n";
}
Достаточно сделать скрипт исполняемым и запустить:
$ chmod +x test.pl
$ ./test.pl
Если скрипт вывел текст "Connection successful.", то можно смело перезапустить трекер:
# systemctl restart mogilefsd