PolarDB PostgreSQL版的物理/逻辑复制支持从WAL Buffer中读取WAL日志,从而将复制进程的WAL日志读I/O优化为内存拷贝。这将显著减少因多个复制进程引发的WAL日志读I/O放大,节省读取WAL日志所消耗的带宽,并降低WAL日志的读取时延,从而有效减少复制时延。
背景
原生PostgreSQL中,复制可以被分为物理复制和逻辑复制。
物理复制:通过传递WAL日志的内容实现Primary和Standby节点之间的同步。
逻辑复制:通过传递WAL日志中解码出的逻辑变更,实现发布端和订阅端节点之间的数据同步。
一个运行中的PostgreSQL允许同时存在多个物理复制和逻辑复制链路,每一个链路由一个对应的WAL sender进程负责读取已经持久化到存储上的WAL日志,完成必要的解析后通过网络发送到下游。每条复制链路之间互相独立,复制进度不受彼此影响。
由于复制进度互相独立,因此每个复制进程都需要各自读取全量的WAL日志并做处理和发送。当复制链路数量较多时,WAL日志的读带宽会呈倍数高于WAL日志的写带宽,消耗大量IOPS。当实例I/O压力较大时,大量的WAL日志读I/O和日常业务的读写I/O会互相影响I/O时延,日常业务的运行速度会变慢,复制延时也会变大。
原生PostgreSQL中,WAL日志产生时,会先被写入到WAL Buffer中,然后再被后台进程或普通进程写入存储。WAL Buffer中的空间会被循环复用,因此WAL Buffer中留存了所有最近产生的WAL日志,也是最大概率会被复制进程使用到的部分。
PolarDB PostgreSQL版支持直接从WAL Buffer中消费已经落盘但依旧留存的WAL日志,从而将复制进程的WAL日志读 I/O优化为内存拷贝。该优化不仅能够极大减少因多个复制进程引发的WAL日志读I/O放大,节省读取WAL日志所消耗的带宽,还可以降低WAL日志的读取时延,从而降低复制时延。
前提条件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(内核小版本14.13.27.0及以上)
您可通过如下语句查看PolarDB PostgreSQL版的内核小版本号:
SELECT version();
使用方法
设置polar_enable_read_from_wal_buffers
参数为on
使其对复制进程生效。默认值为on
。通过控制台设置集群参数详细操作,请参考设置集群参数。
通过polar_monitor插件可查看从WAL Buffer中读取WAL日志的命中情况。
创建polar_monitor插件。
CREATE EXTENSION IF NOT EXISTS polar_monitor;
查看从WAL Buffer中读取WAL日志的命中情况。
SELECT * FROM polar_stat_walsnd_xlog_read();
返回结果如下:
pid | hit | hit_bytes | prefetched | prefetched_bytes | read | read_bytes ---------+------+-----------+------------+------------------+------+------------ 3865685 | 2175 | 251583064 | 0 | 0 | 82 | 10628128 3865751 | 2173 | 251582792 | 0 | 0 | 82 | 10628400 (2 rows)
返回字段描述如下:
列名 | 数据类型 | 描述 |
pid | INTEGER | 复制进程PID。 |
hit | BIGINT | 直接命中WAL Buffer的读I/O次数。 |
hit_bytes | BIGINT | 直接命中WAL Buffer的读I/O字节数。 |
prefetched | BIGINT | 从存储上批量预读取WAL日志并在内存中缓存后,命中内存缓存的读I/O次数。 |
prefetched_bytes | BIGINT | 从存储上批量预读取WAL日志并在内存中缓存后,命中内存缓存的读I/O字节数。 |
read | BIGINT | 从存储上读取WAL日志的读I/O次数。 |
read_bytes | BIGINT | 从存储上读取WAL日志的读I/O字节数。 |