Как стать автором
Обновить

Комментарии 8

Как обычно, какую задачу решаем?

Если вам нужна гарантия, что все WAL сохранены где-то ещё - то начать нужно с вопроса, что вы хотите что бы делала база когда это невозможно. Ну вот буквально, транзакция хочет сделать insert данных. Что делать базе? Разрешить выполнить запись сразу и закоммитить? Всё, тут мы уже нарушили гарантию доставки WAL. У нас есть кусочек WAL, который существует только локально на этой базе и ещё не был никуда скопирован. Для этой задачи нужна синхронная репликация. При том, иметь в виду, что insert в postgresql выполнен будет в любом случае при активной синхронной репликации, синхронная репликация гарантирует что ответ базы "commit выполнен" будет получен после доставки WAL на указанную конфигурацию синхронных реплик. При проблемах с синхронной репликацией останавливается запись данных, но раз просили гарантию сохранности - то вот она цена.

Хотим чтобы реплика могла догнать после существенного отставания репликации?
гарантированно? слот репликации без ограничения, либо архив WAL если он очищается с учётом отставания этой реплики. Хочу обратить внимание, что если archive_command перестаёт работать - то база будет накапливать WAL безгранично, подобно слотам репликации max_slot_wal_keep_size. Зато скорей всего под архив WAL получится выделить куда более вместительное и более дешёвое хранилище. Цена той гарантии, что реплика догонит - потенциально неограниченный расход места на хранение WAL.
после разумного объёма отставания? wal_keep_size либо слот репликации с max_slot_wal_keep_size, либо архив WAL если тот очищается независимо от отставания реплики

Но вообще архив WAL обычно заводят когда нужен point-in-time-recovery, а не для репликации. И это другая задача. А потом уже, раз всё равно пишем архив WAL, - то можно и задействовать restore_command чтобы из него подтягивать недостающие WAL для отстающих реплик, попутно.

В большинстве production систем действительно лучше потерять реплику и переналить заново, чем уронить мастер с переполнением диска. Поэтому мы почти всегда используем только wal_keep_size. Если реплика отстала до requested WAL segment ... has already been removed и ничего не могли сделать после того как мониторинг сказал что реплика отстаёт - то переналить заново. Зато не потеряли мастер.

restore_command, кстати, имеет одно не очень явно задокументированное свойство: он имеет безусловный приоритет над WAL уже сохранёнными в pg_wal. То есть даже если у вас все WAL есть локально у базы во время старта, то всё равно они будут заново читаться из архива. Поэтому если у вас архив wal не очень быстрый на чтение - то restore_command будет замедлять все рестарты баз.

Как обычно, какую задачу решаем?

Чтобы лидер меньше зависел от состояния реплик.

По сути, вот это:

Хотим чтобы реплика могла догнать после существенного отставания репликации?
гарантированно?

Но чтобы еще лидер от этого не помер. Опять же: либо из-за забитого места WAL-ами, либо из-за переутилизации сети. Соответственно, слот репликации без ограничения - сразу нет, wal_keep_size имеет недостатки (которые описаны в статье):

Но у этого метода есть минусы: 

  • Лидер временно может хранить WAL-ов больше, чем указано в параметре wal_keep_size (например, из-за долгой транзакции), которые позже будут удалены. Нет гарантий, что удаленные WAL-ы будут доставлены до реплик;

  • wal_keep_size вынуждает лидера хранить ненужные WAL-ы, которые применены на репликах и просто занимают место.

Но, идея с max_slot_wal_keep_size валидна: нивелируется второй недостаток (вынужденно хранить ненужные WAL-ы), но имеет первый недостаток (который можно попробовать нивелировать "архивной репликацией" кстати).

Поэтому, по сути, "архивная репликация" работает, как вы и написали:

раз всё равно пишем архив WAL, - то можно и задействовать
restore_command чтобы из него подтягивать недостающие WAL для отстающих
реплик, попутно.

По поводу этого:

Поэтому если у вас архив wal не очень быстрый на чтение - то restore_command будет замедлять все рестарты баз

Тоже валидное замечание, спасибо, что отметили. Поэтому, в статье отмечено:

и мы имеем относительно быстрое хранилище, куда складируются WAL-ы, то
нам ничего не мешает отказаться от слотов репликации полностью.

Но да, не отмечено: что такое "относительно быстрое хранилище", поэтому, тут могут быть споры. Я понимаю, что если тащить WAL-ы из той же Москвы в Новосибирск, то идея с архивной репликацией быстро умрет :)

А по поводу поведения restore_command : спасибо, не знал. Век живи - век учись... :)

И спасибо за ценный развернутый комментарий!

Лидер временно может хранить WAL-ов больше, чем указано в параметре wal_keep_size (например, из-за долгой транзакции)

Мастер может в любой конфигурации хранить WAL'ов больше чем указано где-либо потому что ограничения на максимальный объём WAL просто нет.
И нет, wal_keep_size не имеет никакого отношения к долгим транзакциям. У нас REDO, не волнует возраст транзакций ни для crash recovery ни для удержания WAL, нас волнует LSN который записали при чекпойнте и соответственно откуда стартовать recovery. А уже при crash recovery смотрим, встретили ли commit запись в WAL или нет.

Вот то, что wal_keep_size держит постоянно занятый объём, я, впрочем, и вовсе как недостаток не рассматриваю - это вполне неплохой удобный резерв наравне с reserved space в ext4. Надо освободить место - оговариваем, что тогда могут отвалиться дальние/медленные реплики. Зато когда медленные реплики действительно отстают - у нас не начинает исчезать свободное место.

Я понимаю, что если тащить WAL-ы из той же Москвы в Новосибирск, то идея с архивной репликацией быстро умрет :)

Я бы кстати наоборот ожидал что на фиговой сети file shipping репликация будет менее проблемная. WAL'ы в виде файликов неплохо сжимаются и сжатие wal просто добавить для архива (по-моему, это вообще дефолтный режим в wal-g). А вот streaming репликация гоняет несжатые данные. При том, потоковая репликация ходит строго одним TCP коннектом. Если нет своих сетевых инженеров для тюнинга сетевого стека, то кучка маленьких параллельных TCP сессий на нестабильной сети наверняка будут работать лучше чем одно долгоживущее.

Ну и в плюсы репликации через архив можно добавить, что для этого способа не надо прорубать сетевое окно на подключение до рабочих баз через всевозможные VPN и файрволы по пути. Базу можно изолировать в закрытом сетевом контуре, куда извне не подключиться.
Плюс гибкость выбора транспортировки WAL, хоть по RFC 1149 кидать.

А вот streaming репликация гоняет несжатые данные.

Кажется, что при включенном wal_compression и full_page_writes оно-таки жмёт в случае со streaming-replication.
И судя по интернетам - даже на pglz вполне заметно. На 15-ой версии уже и lz4/zstd завезли, так что результаты могут оказаться ещё более интересными.

Да, wal_compression вполне заметно работает, даже при том что только на full page image записях применяется. Сжатие производится до записи WAL как такового, а потому снижает не только объёмы передачи потоковой репликации, но и IO тоже. И к архиву тоже соответственно применяется.

А вот если помимо wal_compression сжимать весь сегмент чем-то ещё сверху - то эффект куда сильнее. Вроде такого

melkij@melkij:/tmp/z$ du -hs *
17M	000000010000003500000034
3,3M	000000010000003500000034.gz
2,2M	000000010000003500000034.zst

Задача - бэкап базы с реплики, инструмент - barman, режим - асинхронная реплика со слотом, задержки - тот же сегмент сети и околонулевые объемы изменений в секунду (зато критичные). Пробовали ставить синхронный коммит, работает даже, но потом убрали.

А какие есть варианты для обеспечения минимальной потери данных на асинхронной реплике при отвале мастера? В лучшем случае, ничего не потерять, или это невозможно?

а делал кто-то репликацию из одиночного сервера постгре в кластер патрони репликацию для плавного перехода в дальнейшем на отказоустойчивый кластер?

Зарегистрируйтесь на Хабре, чтобы оставить комментарий