Redrock Postgres 搜索 英文
版本: 14 / 15 / 16 / 17

47.9 针对逻辑解码的大事务流传输 #

仅当事务实际上已提交时,才会调用基本输出插件回调(例如,begin_cbchange_cbcommit_cbmessage_cb)。仍然根据事务日志对更改进行解码,但仅在提交时传递给输出插件(如果事务中止,则丢弃这些更改)。

这意味着,虽然解码会逐步进行,且可以溢出到磁盘以控制内存使用情况,但所有已解码的更改都必须在事务最终提交时(或更确切地说,在从事务日志中解码提交)进行传输。根据事务大小和网络带宽,传输时间可能会显著增加应用时延。

为了减少因为大体积事务而引起的应用时延,输出插件可能提供更多回调来支持增量事务的进行中的事务的流。有几个流回调是必需的(stream_start_cbstream_stop_cbstream_abort_cbstream_commit_cbstream_change_cb)和两个可选回调(stream_message_cbstream_truncate_cb)。另外,如果需要支持分两阶段执行的命令的流,那么必须提供更多回调。(有关详细信息,请参阅第 47.10 节)。

在对进行中的事务进行流传输时,变更(和消息)按块流式传输,该块由 stream_start_cbstream_stop_cb 回调进行分界。一旦所有解码的变更都被传输,即可使用 stream_commit_cb 回调提交事务(或可能使用 stream_abort_cb 回调中止事务)。如果支持分两阶段执行的提交,则可以使用 stream_prepare_cb 回调来准备事务,使用 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 表插入,但没有解码主表插入。

即使在对大体积事务进行流传输时,变更仍按提交顺序应用,保留与非流模式相同的保证。