Назад | Перейти на главную страницу

Обновите Postgres на рабочем сервере без простоев

У меня есть производственный сервер с Postgres 9.4. База данных> 10 ГБ. Возможно ли обновление до Postgres 9.5 без простоев и без потери данных?

В руководствах по обновлению рекомендуется останавливать Postgres во время выполнения sudo pg_upgradecluster 9.4 main, но это может занять много времени. Обновление кластера 10 ГБ может занять несколько часов!

Я тоже пробовал pg_dump mydb > db.sql. Удаление базы данных и повторная вставка дампа в PG 9.4 (psql -d mydb -f db.sql) заняло около 50 минут.

Но вставка дампа в PG 9.5 закончилась только через более чем 7 часов. Особенно создание индекса было очень медленным ...

2016-07-18 00:13:55 CEST [60358-5] ERROR:  canceling autovacuum task
2016-07-18 00:13:55 CEST [60358-6] CONTEXT:  automatic analyze of table ...
2016-07-18 00:36:20 CEST [60366-1] ERROR:  canceling autovacuum task
2016-07-18 00:36:20 CEST [60366-2] CONTEXT:  automatic analyze of table ...
2016-07-18 04:21:40 CEST [60361-1] ERROR:  canceling autovacuum task
2016-07-18 04:21:40 CEST [60361-2] CONTEXT:  automatic analyze of table ...
2016-07-18 07:55:19 CEST [61316-1] ERROR:  canceling autovacuum task
2016-07-18 07:55:19 CEST [61316-2] CONTEXT:  automatic analyze of table ...

Так что ни pg_upgradecluster ни pg_dump приемлемое решение. Даже с PG 4 у вас будет минимум 50 минут простоя. Следовательно: как можно обновить базы данных на производственных серверах или больших кластерах master-slave без простоев и потерь данных?

Без некоторой магии кластеризации простои невозможны.

Некоторые другие возможности:

  1. использовать pg_upgrade с --link вариант. При использовании этой опции исходные файлы БД не копируются, а жестко связаны с новым каталогом, что значительно ускоряет процесс. Обратите внимание, что это навсегда изменит исходные файлы БД.
  2. использовать pg_dump и восстановить в новой базе данных. Вы можете значительно сократить необходимое время, отключив синхронную запись в новой базе данных (fsync = false в конфигурационном файле нового экземпляра PG)
  3. установите новый экземпляр PG и позвольте ему работать на другом порту. Затем используйте pg_dump загрузить по сети дамп в новый экземпляр. Когда закончите, поменяйте порты местами и используйте новый экземпляр.

Я думаю, вы уже решили это, так что, возможно, для других с аналогичными проблемами.

После нескольких лет работы с postgresql с версии 8.4 до последней версии 9.6 я бы порекомендовал для этих случаев - не «обновляться». Если возможно, создайте новую машину или новый облачный экземпляр с последней версией используемой вами ОС (очень важно - предотвращает множество проблем) и новейшей версией pg и дублирующими данными.

Как дублировать данные зависит от вашего приложения, версии PostgreSQL и окружающей среды. База данных ~ 10 ГБ не такая большая, так что вам подойдет. Я работаю с dbs> 400 ГБ, так что представьте себе множество проблем ...

  • Pg_dump 9.4 уже позволяет выполнять дамп в формате каталога с несколькими заданиями с использованием нескольких ядер ЦП, что может значительно снизить время дампа - если у вас нет всего в одной большой таблице :-)
  • Или для pg 9.4+ вы можете использовать расширение pglogical, как упоминалось ранее, что действительно отличное решение, но имейте в виду - чтобы запустить pglogical на мастере, вы должны перезапустить postgres, потому что расширение должно быть добавлено в файл postgresql.conf в shared_preload_libraries = 'pglogical' - посмотреть здесь: http://postgresql.freeideas.cz/pglogical-postgresql-9-6-small-hints-debian/ Поэтому я настоятельно рекомендую протестировать его на другом экземпляре с той же версией раньше! И чтобы переключиться на новый экземпляр, запланируйте некоторое короткое окно обслуживания для переключения клиентов на новую базу данных - если строка подключения не жестко прописана в приложении :-) - но в этом случае вы можете подготовить pgbouncer на старой машине с подключениями, настроенными на новую машину, остановите старую базу данных, переключите порт pg (предположим, 5432) на pgbouncer и обработайте строки подключения позже, если это возможно ...
  • Или, может быть, ваше приложение не получает так много новых данных, и вы можете использовать последние резервные копии и вставки / обновления вилки в своем приложении на обеих машинах? И переключать клиентов, когда уверены, что все работает?

Я видел варианты всех этих сценариев в реальной жизни. Так что веселитесь! Скрещиваю пальцы :-)

Обновление (почти) без простоев должно быть возможно с логический. По крайней мере, для PostgreSQL> = 9.4 и новее он должен работать.

Это относительно новый проект (2016 г.), основанный на коде из Двунаправленная репликация для PostgreSQL. Для установки вам понадобится Репозиторий 2ndQuadrant.

Описание использования в README, требуется перезапуск БД (необходимо обновить конфигурацию репликации), но, по крайней мере, это не должно вызывать простоя в несколько часов.

в отличие репмгр, pglogical предназначен для одноразовой репликации БД, что займет намного больше времени, чем копирование двоичных файлов WAL.

Сначала включите расширение для каждой БД, которую необходимо скопировать (обновить):

CREATE EXTENSION pglogical;

В настоящее время все команды необходимо выполнять от имени суперпользователя (postgres). Начнем с создания «главного узла» (provider):

SELECT pglogical.create_node(
    node_name := 'provider1',
    dsn := 'host=providerhost port=5432 dbname=db'
);

и пометьте схемы для репликации:

SELECT pglogical.replication_set_add_all_tables('default', ARRAY['public']);

и репликация последовательностей:

SELECT pglogical.replication_set_add_all_sequences('default', ARRAY['public']);

Обратите внимание, что для каждой таблицы требуется первичный ключ, иначе репликация не начнется. В отличие от других методов резервного копирования, здесь важна согласованность таблиц.

Продолжайте с «резервным узлом» (subscriber)

SELECT pglogical.create_node(
    node_name := 'subscriber1',
    dsn := 'host=thishost port=5432 dbname=db'
);

и наконец запускаем репликацию:

SELECT pglogical.create_subscription(
    subscription_name := 'subscription1',
    provider_dsn := 'host=providerhost port=5432 dbname=db'
);