lesson ── postgres-labs ── ~22 мин ── 7 шагов
Раньше эта лаба показывала только primary-сторону на одном сервере. Теперь у тебя живая пара: primary (узел pg) и физический standby, который при старте сам снял базовую копию через pg_basebackup и встал в recovery. У тебя два пульта: вкладка client смотрит на primary, вкладка standby-cli - на standby.
Пройди связку с обеих сторон. Каждый шаг сначала предскажи вывод, потом проверь на нужном узле.
интерактивный sandbox
Поднимется контейнер postgreslab/postgres-base с PostgreSQL 17 и psql. В браузере откроется терминал, база lab уже настроена. Каждый шаг проверяется автоматически. Сеть air-gapped, наружу контейнер не ходит.
stack ── PostgreSQL 17 · psql · 1 GB RAM · air-gapped · самоуничтожается через 45 мин простоя
На вкладке client (это primary) спроси, в режиме ли восстановления узел. Primary принимает запись, значит в recovery он быть не должен.
SELECT pg_is_in_recovery();
Предскажи: true или false вернёт primary?
✓ primary не в recovery - он ведущий и принимает запись.
Переключись на вкладку standby-cli. Этот узел поднялся из базовой копии и применяет журнал primary, то есть он в постоянном восстановлении.
SELECT pg_is_in_recovery();
Предскажи значение для standby и сравни с тем, что было на primary.
standby не ведущий: он только применяет чужой журнал, запись на него закрыта.
✓ standby в recovery (true) - принимает и проигрывает журнал primary.
Вернись на вкладку client. На primary есть представление pg_stat_replication: одна строка на каждый подключённый walsender.
SELECT application_name, state FROM pg_stat_replication;
Предскажи: будет ли там строка, и какое state у догнавшего реплику потока - startup, catchup или streaming?
✓ state=streaming - standby подключён и тянет журнал в реальном времени.
Раньше ты заводил слот на одиноком сервере, и он висел с active=false. Здесь у слота есть реальный потребитель - standby.
SELECT slot_name, active, restart_lsn FROM pg_replication_slots
WHERE slot_name = 'standby_slot';
Предскажи значение колонки active теперь, когда standby подключён.
✓ active=true - слот занят standby и держит WAL ровно до его позиции.
Всё ещё на вкладке client (primary). Вставь одну строку в таблицу repl_demo - дальше проверим, доедет ли она до standby сама.
INSERT INTO repl_demo (id, note) VALUES (1, 'streamed');
Предскажи: появится ли строка на primary сразу после INSERT?
✓ Строка на primary записана и попала в WAL.
Переключись на вкладку standby-cli. Ты НЕ вставлял сюда ничего: запись на standby закрыта. Строка может появиться только одним путём - примениться из журнала primary.
SELECT note FROM repl_demo WHERE id = 1;
Предскажи: окажется ли здесь строка 'streamed', которую ты вставлял на primary?
Если пусто - проверка повторится; дай реплике мгновение применить журнал.
✓ Строка доехала. standby проиграл WAL primary и увидел вставку.
Остаёмся на standby-cli. У реплики две позиции журнала: сколько она приняла по сети (receive) и сколько уже применила (replay).
SELECT pg_last_wal_receive_lsn() AS received,
pg_last_wal_replay_lsn() AS replayed;
Предскажи: когда standby догнал primary, replay будет меньше received, равен ему или больше?
✓ replay догнал received - standby применил всё, что принял. Лага нет.
Физический standby снимается с primary через pg_basebackup и догоняет журнал потоком. На primary его видно в pg_stat_replication, а слот репликации держит WAL до позиции standby. На standby pg_last_wal_replay_lsn показывает, до какого места применён журнал; когда он сравнялся с receive_lsn, реплика догнала primary.
команды
SELECT pg_is_in_recovery();primary этот узел или standbySELECT state FROM pg_stat_replication;кто стримит с primary и в каком состоянииSELECT active FROM pg_replication_slots;держит ли слот WAL для потребителяSELECT pg_last_wal_replay_lsn();до какого места standby применил журналконцепции