46.9. Потоковая передача больших транзакций для логического декодирования#
46.9. Потоковая передача больших транзакций для логического декодирования #
Все основные обратные вызовы плагина вывода (например, begin_cb
,
change_cb
, commit_cb
и
message_cb
) вызываются только при фактическом коммите транзакции. Изменения все еще декодируются из журнала транзакций, но передаются плагину вывода только при коммите (и отбрасываются, если транзакция отменяется).
Это означает, что декодирование происходит постепенно и может быть сброшено на диск для контроля использования памяти, но все декодированные изменения должны быть переданы при финальном коммите транзакции (или точнее, когда коммит декодируется из журнала транзакций). В зависимости от размера транзакции и пропускной способности сети время передачи может значительно увеличить задержку применения.
Для сокращения задержки применения, вызванной большими транзакциями, выходной плагин может предоставить дополнительные обратные вызовы для поддержки инкрементальной передачи данных в процессе выполнения транзакций. Существуют несколько обязательных обратных вызовов для передачи данных (stream_start_cb
, stream_stop_cb
, stream_abort_cb
, stream_commit_cb
и stream_change_cb
) и два дополнительных обратных вызова (stream_message_cb
и stream_truncate_cb
). Кроме того, если требуется поддержка передачи данных двухфазных команд, необходимо предоставить дополнительные обратные вызовы. (См. Раздел 46.10 для получения подробной информации).
При потоковой передаче транзакции изменения (и сообщения) передаются блоками, отмеченными обратными вызовами stream_start_cb
и stream_stop_cb
. После передачи всех декодированных изменений транзакцию можно зафиксировать с помощью обратного вызова stream_commit_cb
(или, возможно, отменить с помощью обратного вызова stream_abort_cb
). Если поддерживаются двухфазные коммиты, транзакцию можно подготовить с помощью обратного вызова stream_prepare_cb
, выполнить COMMIT PREPARED
с использованием обратного вызова commit_prepared_cb
или отменить с помощью обратного вызова rollback_prepared_cb
.
Один пример последовательности вызовов обратного вызова потокового ввода-вывода для одной транзакции может выглядеть так:
stream_start_cb(...); <-- start of first block of changes stream_change_cb(...); stream_change_cb(...); stream_message_cb(...); stream_change_cb(...); ... stream_change_cb(...); stream_stop_cb(...); <-- end of first block of changes stream_start_cb(...); <-- start of second block of changes stream_change_cb(...); stream_change_cb(...); stream_change_cb(...); ... stream_message_cb(...); stream_change_cb(...); stream_stop_cb(...); <-- end of second block of changes [a. when using normal commit] stream_commit_cb(...); <-- commit of the streamed transaction [b. when using two-phase commit] stream_prepare_cb(...); <-- prepare the streamed transaction commit_prepared_cb(...); <-- commit of the prepared transaction
Фактическая последовательность вызовов обратных вызовов может быть, конечно, более сложной. Могут быть блоки для нескольких потоковых транзакций, некоторые из транзакций могут быть прерваны и т. д.
Аналогично поведению сброса на диск, потоковая передача данных запускается, когда общее количество изменений, декодированных из WAL (для всех транзакций в процессе выполнения), превышает лимит, определенный параметром logical_decoding_work_mem
. В этот момент выбирается самая большая транзакция верхнего уровня (измеряемая по объему памяти, используемой для декодирования изменений), которая будет передаваться потоком. Однако в некоторых случаях нам все равно приходится выполнять сброс на диск, даже если потоковая передача данных включена, потому что мы превышаем пороговое значение памяти, но все еще не декодировали полную кортеж, например, только вставили данные в таблицу toast, но не в основную таблицу.
Даже при потоковой передаче больших транзакций изменения всё равно применяются в порядке коммита, сохраняя те же гарантии, что и в режиме без потоковой передачи.