Отставание / остановка репликации
Standby/реплика отстаёт от primary, или репликация полностью остановилась. Это дерево шаг за шагом сужает тип отставания (растёт, постоянное или остановка), чтобы дойти до первопричины: ошибка применения, узкое место однопоточного применения, конфликт восстановления или повреждение.
Как ведёт себя отставание?
Сначала оцените ситуацию. Посмотрите на поток реплики и метрику отставания: отставание растёт со временем, застыло на постоянном уровне или применение полностью остановилось? Это делит расследование на три основные ветки.
SELECT client_addr, state, write_lag, flush_lag, replay_lag,
pg_wal_lsn_diff(sent_lsn, replay_lsn) AS bytes_behind
FROM pg_stat_replication;- Применение полностью остановлено / есть ошибка
- Отставание продолжает расти (не может догнать)
- Отставание постоянное, но подозревается долгий запрос
- Сильно отстаёт / выглядит несогласованной
Что говорит ошибка применения?
Если репликация остановилась, обычно в применяемом событии есть ошибка. Посмотрите на сообщение об ошибке: на цели нет строки/таблицы, конфликт первичного ключа или обрыв соединения/сети?
SHOW REPLICA STATUS\G -- Last_Error, Last_SQL_Error, Replica_IO_Running, Replica_SQL_Running- Ошибка конфликтующей/отсутствующей строки или таблицы
- Сеть/соединение оборвалось, поток IO остановлен
Почему не может догнать?
Если отставание продолжает расти, реплика не успевает за скоростью записи на primary. Узкое место — однопоточное применение или медленный диск/IO реплики? Посмотрите на состояние рабочего процесса применения и ожидания IO.
SHOW REPLICA STATUS\G -- Seconds_Behind_Source and apply thread state
SELECT * FROM performance_schema.replication_applier_status_by_worker;- Однопоточное применение + большая нагрузка на запись
- Медленный диск/IO реплики
Есть ли долгий запрос на standby?
Долгий запрос на standby только для чтения может блокировать применение (recovery). В PostgreSQL так возникает конфликт восстановления. Посмотрите на активные запросы и счётчики конфликтов на standby.
SELECT now()-query_start AS dur, pid, state, query
FROM pg_stat_activity WHERE state='active' ORDER BY query_start;
SELECT confl_snapshot, confl_lock, confl_bufferpin FROM pg_stat_database_conflicts WHERE datname=current_database();- Да, долгий запрос блокирует применение
- Нет, запроса нет, но отставание всё равно есть
Первопричина: ошибка применения (конфликт данных)
Реплика застряла на событии, которое не может применить: на цели нет строки, конфликт первичного ключа или отсутствует таблица. Устраните причину несогласованности вместо слепого пропуска.
Первопричина: обрыв соединения / сети
Поток-получатель (IO/receiver) не может подключиться к primary. Проблема может быть в сети, аутентификации или накопленных/удалённых сегментах журнала.
Первопричина: узкое место однопоточного применения
Пока primary пишет параллельно, реплика применяет изменения в одной последовательности и не успевает. Распараллельте применение.
Первопричина: узкое место IO на реплике
Поток применения ждёт диск, а не CPU. Хранилище реплики не успевает за скоростью записи primary.
Первопричина: конфликт восстановления на standby
Долгий запрос только для чтения на standby блокирует применение изменений с primary (конфликт vacuum/блокировки). PostgreSQL решает это, задерживая применение или отменяя запрос.
Первопричина: реплика слишком отстала / повреждена — пересоздайте её
Реплика отстала слишком сильно для восстановления, нужные журналы удалены или данные несогласованы. Самый безопасный путь — пересоздать её из свежего бэкапа.