Время от времени приходится сталкиваться с вопросом "У нас отваливаются запросы на реплике, мы включили hot_standby_feedback, но запросы на реплике все равно периодически отваливаются. Почему?" После прочтения документации, может сложится впечателение что фидбек решает проблемы отмены запросов и если его включить то конфликты пропадут. Однако это не совсем так. В этой статье мы разберемся что такое фидбек, как он работает и какие проблемы призван решать.
English version available in our company's blog.
Для начала обратимся к официальной документации:
Как видно из описания, стендбай отправляет информацию о запросах которые выполняются в данный момент на стендбае. Что это за информация?
По-умолчанию фидбек отключен, и в таком случае wal receiver отправляет только информацию о том какие участки журнала транзакций записаны, синхронизированы и проиграны (см. pg_stat_replication). Для включения функции отправки фидбека нужно установить hot_standby_feedback = on и сделать релоад потсгреса.
Теперь обратимся к исходным кодам, а точнее посмотрим код wal receiver процесса, который работает на стендбай сервере и выполняет задачу приема WAL журнала с мастер сервера. Нам понадобится файл src/backend/replication/walreceiver.c и функция XLogWalRcvSendHSFeedback, именно она занимается отправкой фидбека. Отправка фидбека выполняется при соблюдении следующих условий
Когда идентификатор самой старой транзакции вычислен, отнимаем значение vacuum_defer_cleanup_age от полученного значения. Параметр vacuum_defer_cleanup_age это мера откладывания вакуума которая предшествовала фидбеку в ранних версиях postgresql. Вот как описан параметр в оф. документации:
vacuum_defer_cleanup_age - Specifies the number of transactions by which VACUUM and HOT updates will defer cleanup of dead row versions. The default is zero transactions, meaning that dead row versions can be removed as soon as possible, that is, as soon as they are no longer visible to any open transaction. You may wish to set this to a non-zero value on a primary server that is supporting hot standby servers, as described in Section 25.5. This allows more time for queries on the standby to complete without incurring conflicts due to early cleanup of rows. However, since the value is measured in terms of number of write transactions occurring on the primary server, it is difficult to predict just how much additional grace time will be made available to standby queries. This parameter can only be set in the postgresql.conf file or on the server command line.
Таким образом значение oldest xmin будет равно идентификатору самой старой транзакции запущенной на стендбае с вычетом vacuum_defer_cleanup_age, либо идентификатору самой старой транзакции которая нужна слоту репликации с вычетом vacuum_defer_cleanup_age.
Однако это не всё, теперь нам нужно учесть эпоху, ведь может получиться так что изменилась эпоха и счетчик транзакций начался заново. Для этого мы берем значение следующей транзакции и сравниваем с ранее полученным значением oldestx min. Если получилось так что значение oldest xmin больше чем значение следующей транзакции, то уменьшаем значение эпохи на единицу.
Теперь осталось собрать наше фидбек сообщение и отправить его мастеру. Для этого инициализируем пустое сообщение, добавляем метку определяющую что сообщение является фидбеком (это нужно мастеру, т.к. от wal receiver'a приходят разные сообщение и мастер обрабатывает их по разному), затем добавляем отметку времени, значение oldest xmin и значение эпохи. Теперь отправляем сообщение мастеру с помощью функции walrcv_send (на самом деле это обертка над libpqrcv_send). На этом месте работа функции завершается.
В дальнейшем сообщение будет принято wal sender процессом который запущен на мастере или upstream сервере. Это значение будет записано в его внутреннюю структуру MyPgXact->xmin. Аналогичная стурктура есть у каждого бэкенда. В дальнейшем когда вакуум перед обработкой таблицы будет выполнять определение самой старой транзакции (с уже известной нам функцией GetOldestXmin) значение MyPgXact->xmin принадлежащее wal sender процессу также будет принято во внимание. Вычисленный oldest xmin будет использоваться для проверки tuple'ов на предмет видимости открытыми транзакциям. Если tuple еще видим хоть одной транзакции, вакуумировать его нельзя.
Таким образом wal sender выступает посредником для стендбай сервера, и если вакуум должен обработать записи которые видны транзакциям на стендбай сервере, он будет вынужден пропустить эти записи.
Резюме. Параметр hot_standby_feedback никак не связан с разрешением конфликтов при репликации и всего лишь позволяет избежать отмены запросов на стендбае в случае когда записи затронутые транзакцией должны быть обработаны вакуумом на мастер сервере.
Спасибо за внимание!
English version available in our company's blog.
На главную "Virtualizing Linux"
English version available in our company's blog.
Для начала обратимся к официальной документации:
hot_standby_feedback - Specifies whether or not a hot standby will send feedback to the primary or upstream standby about queries currently executing on the standby. This parameter can be used to eliminate query cancels caused by cleanup records, but can cause database bloat on the primary for some workloads. Feedback messages will not be sent more frequently than once per wal_receiver_status_interval. The default value is off. This parameter can only be set in the postgresql.conf file or on the server command line.
Как видно из описания, стендбай отправляет информацию о запросах которые выполняются в данный момент на стендбае. Что это за информация?
По-умолчанию фидбек отключен, и в таком случае wal receiver отправляет только информацию о том какие участки журнала транзакций записаны, синхронизированы и проиграны (см. pg_stat_replication). Для включения функции отправки фидбека нужно установить hot_standby_feedback = on и сделать релоад потсгреса.
Теперь обратимся к исходным кодам, а точнее посмотрим код wal receiver процесса, который работает на стендбай сервере и выполняет задачу приема WAL журнала с мастер сервера. Нам понадобится файл src/backend/replication/walreceiver.c и функция XLogWalRcvSendHSFeedback, именно она занимается отправкой фидбека. Отправка фидбека выполняется при соблюдении следующих условий
- wal_receiver_status_interval должно быть больше нуля;
- hot_standby_feedback должен быть включен (on).
Когда идентификатор самой старой транзакции вычислен, отнимаем значение vacuum_defer_cleanup_age от полученного значения. Параметр vacuum_defer_cleanup_age это мера откладывания вакуума которая предшествовала фидбеку в ранних версиях postgresql. Вот как описан параметр в оф. документации:
vacuum_defer_cleanup_age - Specifies the number of transactions by which VACUUM and HOT updates will defer cleanup of dead row versions. The default is zero transactions, meaning that dead row versions can be removed as soon as possible, that is, as soon as they are no longer visible to any open transaction. You may wish to set this to a non-zero value on a primary server that is supporting hot standby servers, as described in Section 25.5. This allows more time for queries on the standby to complete without incurring conflicts due to early cleanup of rows. However, since the value is measured in terms of number of write transactions occurring on the primary server, it is difficult to predict just how much additional grace time will be made available to standby queries. This parameter can only be set in the postgresql.conf file or on the server command line.
Таким образом значение oldest xmin будет равно идентификатору самой старой транзакции запущенной на стендбае с вычетом vacuum_defer_cleanup_age, либо идентификатору самой старой транзакции которая нужна слоту репликации с вычетом vacuum_defer_cleanup_age.
Однако это не всё, теперь нам нужно учесть эпоху, ведь может получиться так что изменилась эпоха и счетчик транзакций начался заново. Для этого мы берем значение следующей транзакции и сравниваем с ранее полученным значением oldestx min. Если получилось так что значение oldest xmin больше чем значение следующей транзакции, то уменьшаем значение эпохи на единицу.
Теперь осталось собрать наше фидбек сообщение и отправить его мастеру. Для этого инициализируем пустое сообщение, добавляем метку определяющую что сообщение является фидбеком (это нужно мастеру, т.к. от wal receiver'a приходят разные сообщение и мастер обрабатывает их по разному), затем добавляем отметку времени, значение oldest xmin и значение эпохи. Теперь отправляем сообщение мастеру с помощью функции walrcv_send (на самом деле это обертка над libpqrcv_send). На этом месте работа функции завершается.
В дальнейшем сообщение будет принято wal sender процессом который запущен на мастере или upstream сервере. Это значение будет записано в его внутреннюю структуру MyPgXact->xmin. Аналогичная стурктура есть у каждого бэкенда. В дальнейшем когда вакуум перед обработкой таблицы будет выполнять определение самой старой транзакции (с уже известной нам функцией GetOldestXmin) значение MyPgXact->xmin принадлежащее wal sender процессу также будет принято во внимание. Вычисленный oldest xmin будет использоваться для проверки tuple'ов на предмет видимости открытыми транзакциям. Если tuple еще видим хоть одной транзакции, вакуумировать его нельзя.
Таким образом wal sender выступает посредником для стендбай сервера, и если вакуум должен обработать записи которые видны транзакциям на стендбай сервере, он будет вынужден пропустить эти записи.
Резюме. Параметр hot_standby_feedback никак не связан с разрешением конфликтов при репликации и всего лишь позволяет избежать отмены запросов на стендбае в случае когда записи затронутые транзакцией должны быть обработаны вакуумом на мастер сервере.
Спасибо за внимание!
English version available in our company's blog.
На главную "Virtualizing Linux"
Комментариев нет:
Отправить комментарий