12 KiB
aliases | tags | date | zero-link | parents | linked | |||||
---|---|---|---|---|---|---|---|---|---|---|
|
|
|
|
Физическая репликация
-
Создаем сеть, запоминаем адрес
docker network create pgnet docker network inspect pgnet | grep Subnet # Запомнить маску сети
-
Поднимаем мастер
docker run -dit -v "$PWD/volumes/pgmaster/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "5432:5432" --restart=unless-stopped --network=pgnet --name=pgmaster postgres
-
Меняем postgresql.conf на мастере
ssl = off wal_level = replica max_wal_senders = 4 # expected slave num
-
Подключаемся к мастеру и создаем пользователя для репликации
docker exec -it pgmaster su - postgres -c psql create role replicator with login replication password 'pass'; exit
-
Добавляем запись в
pgmaster/pg_hba.conf
сsubnet
с первого шагаhost replication replicator __SUBNET__ md5
-
Перезапустим мастер
docker restart pgmaster
-
Сделаем бэкап для реплик
docker exec -it pgmaster bash mkdir /pgslave pg_basebackup -h pgmaster -D /pgslave -U replicator -v -P --wal-method=stream exit
-
Копируем директорию себе
docker cp pgmaster:/pgslave volumes/pgslave/
-
Создадим файл, чтобы реплика узнала, что она реплика
touch volumes/pgslave/standby.signal
-
Меняем
postgresql.conf
на репликеpgslave
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgslave'
-
Запускаем реплику
pgslave
docker run -dit -v "$PWD/volumes/pgslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "15432:5432" --network=pgnet --restart=unless-stopped --name=pgslave postgres
-
Запустим вторую реплику
pgasyncslave
-
скопируем бэкап
docker cp pgmaster:/pgslave volumes/pgasyncslave/
-
изменим настройки
pgasyncslave/postgresql.conf
primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgasyncslave'
-
дадим знать что это реплика
touch volumes/pgasyncslave/standby.signal
-
запустим реплику
pgasyncslave
docker run -dit -v "$PWD/volumes/pgasyncslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "25432:5432" --network=pgnet --restart=unless-stopped --name=pgasyncslave postgres
-
-
Убеждаемся что обе реплики работают в асинхронном режиме на
pgmaster
docker exec -it pgmaster su - postgres -c psql select application_name, sync_state from pg_stat_replication; exit;
-
Включаем синхронную репликацию на
pgmaster
-
меняем файл
pgmaster/postgresql.conf
synchronous_commit = on synchronous_standby_names = 'FIRST 1 (pgslave, pgasyncslave)'
-
перечитываем конфиг
docker exec -it pgmaster su - postgres -c psql select pg_reload_conf(); exit;
-
-
Убеждаемся, что реплика стала синхронной
docker exec -it pgmaster su - postgres -c psql select application_name, sync_state from pg_stat_replication; exit;
-
Создадим тестовую таблицу на
pgmaster
и проверим репликациюdocker exec -it pgmaster su - postgres -c psql create table test(id bigint primary key not null); insert into test(id) values(1); select * from test; exit;
-
Проверим наличие данных на
pgslave
docker exec -it pgslave su - postgres -c psql select * from test; exit;
-
Проверим наличие данных на
pgasyncslave
docker exec -it pgasyncslave su - postgres -c psql select * from test; exit;
-
Попробуем сделать
insert
наpgslave
docker exec -it pgslave su - postgres -c psql insert into test(id) values(2); exit;
-
Укладываем репилку
pgasyncslave
и проверяем работуpgmaster
иpgslave
docker stop pgasyncslave docker exec -it pgmaster su - postgres -c psql select application_name, sync_state from pg_stat_replication; insert into test(id) values(2); select * from test; exit; docker exec -it pgslave su - postgres -c psql select * from test; exit;
-
Укладываем репилку
pgslave
и проверяем работуpgmaster
, а потом возвращаем репликуpgslave
- terminal 1
docker stop pgslave docker exec -it pgmaster su - postgres -c psql select application_name, sync_state from pg_stat_replication; insert into test(id) values(3); exit;
- terminal 2
docker start pgslave
- terminal 1
-
Возвращаем вторую реплику
pgasyncslave
docker start pgasyncslave
-
Убиваем мастер
pgmaster
docker stop pgmaster
-
Запромоутим реплику
pgslave
docker exec -it pgslave su - postgres -c psql select pg_promote(); exit;
-
Пробуем записать в новый мастер
pgslave
docker exec -it pgslave su - postgres -c psql insert into test(id) values(4); exit;
-
Настраиваем репликацию на
pgslave
(pgslave/postgresql.conf
)- изменяем конфиг
synchronous_commit = on synchronous_standby_names = 'ANY 1 (pgmaster, pgasyncslave)'
- перечитываем конфиг
docker exec -it pgslave su - postgres -c psql select pg_reload_conf(); exit;
- изменяем конфиг
-
Подключим вторую реплику
pgasyncslave
к новому мастеруpgslave
- изменяем конфиг
pgasyncslave/postgresql.conf
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgasyncslave'
- перечитываем конфиг
docker exec -it pgasyncslave su - postgres -c psql select pg_reload_conf(); exit;
- изменяем конфиг
-
Проверяем что к новому мастеру
pgslave
подключена реплика и она работаетdocker exec -it pgslave su - postgres -c psql select application_name, sync_state from pg_stat_replication; insert into test(id) values (5) select * from test; exit; docker exec -it pgasyncslave su - postgres -c psql select * from test; exit;
-
Восстановим старый мастер
pgmaster
как реплику- Помечаем как реплику
touch volumes/pgmaster/standby.signal
- Изменяем конфиг
pgmaster/postgresql.conf
primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgmaster'
- Запустим
pgmaster
docker start pgmaster
- Убедимся что
pgmaster
подключился как реплика кpgslave
docker exec -it pgslave su - postgres -c psql select application_name, sync_state from pg_stat_replication; exit;
- Помечаем как реплику
Логическая репликация
-
Меняем
wal_level
для текущего мастераpgslave
- Изменяем настройки
pgslave/postgresql.conf
wal_level = logical
- Перезапускаем
pgslave
docker restart pgslave
- Изменяем настройки
-
Создадим публикацию в
pgslave
docker exec -it pgslave su - postgres -c psql GRANT CONNECT ON DATABASE postgres TO replicator; GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator; create publication pg_pub for table test; exit;
-
Создадим новый сервер
pgstandalone
для логической репликацииdocker run -dit -v "$PWD/volumes/pgstandalone/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "35432:5432" --restart=unless-stopped --network=pgnet --name=pgstandalone postgres
-
Копируем файлы c
pgslave
вpgstandalone
и восстанавливаемdocker exec -it pgslave su - postgres pg_dumpall -U postgres -r -h pgslave -f /var/lib/postgresql/roles.dmp pg_dump -U postgres -Fc -h pgslave -f /var/lib/postgresql/schema.dmp -s postgres exit; docker cp pgslave:/var/lib/postgresql/roles.dmp . docker cp roles.dmp pgstandalone:/var/lib/postgresql/roles.dmp docker cp pgslave:/var/lib/postgresql/schema.dmp . docker cp schema.dmp pgstandalone:/var/lib/postgresql/schema.dmp docker exec -it pgstandalone su - postgres psql -f roles.dmp pg_restore -d postgres -C schema.dmp exit
-
Создаем подписку на
pgstandalone
docker exec -it pgstandalone su - postgres -c psql CREATE SUBSCRIPTION pg_sub CONNECTION 'host=pgslave port=5432 user=replicator password=pass dbname=postgres' PUBLICATION pg_pub; exit;
-
Убеждаемся что репликация запущена
docker exec -it pgstandalone su - postgres -c psql select * from test; exit;
-
Сделаем конфликт в данных
- Вставляем данные в подписчике
pgstandalone
docker exec -it pgstandalone su - postgres -c psql insert into test values(9); exit;
- Вставляем данные в паблишере
pgslave
docker exec -it pgslave su - postgres -c psql insert into test values(9); insert into test values(10); exit;
- Убеждаемся что записи с id 10 не появилось на
pgstandalone
docker exec -it pgstandalone su - postgres -c psql select * from test; exit;
- Посмотрим в логи
pgstandalone
и убедимся что у нас произошел разрыв репликацииdocker logs pgstandalone
2023-03-27 16:15:02.753 UTC [258] ERROR: duplicate key value violates unique constraint "test_pkey" 2023-03-27 16:15:02.753 UTC [258] DETAIL: Key (id)=(9) already exists. 2023-03-28 18:30:42.893 UTC [108] CONTEXT: processing remote data for replication origin "pg_16395" during message type "INSERT" for replication target relation "public.test" in transaction 739, finished at 0/3026450
- Вставляем данные в подписчике
-
Исправляем конфликт
docker exec -it pgstandalone su - postgres -c psql SELECT pg_replication_origin_advance('pg_16395', '0/3026451'::pg_lsn); # message from log + 1 ALTER SUBSCRIPTION pg_sub ENABLE; select * from test; exit;