背景
1、产品的问题点
- PG 物理Standby节点不支持解析逻辑日志
2、问题点背后涉及的技术原理
- 解析逻辑日志需要记录解析的WAL日志LSN位点(通过slot功能实现), 以便实例重启或解析任务重启后实现断点续传, 但是物理Standby节点是RO模式, 不支持写入(slot lsn位点记录), 因此Standby节点不支持解析逻辑日志.
- 另一方面, 为了解析逻辑日志, 需要保留catalog的旧版本, 用于读取对应WAL record对应数据库对象(例如table)当时对应的数据结构, 从而解析出WAL record的逻辑数据. 而这个动作需要与VACUUM垃圾回收联动, 防止vacuum把catalog的旧版本清理掉(例如数据库发生DDL(如修改了表结构), 会导致catalog的版本发生变化, 老的catalog记录就变成旧版本, 旧版本可能被vacuum垃圾回收)
3、这个问题将影响哪些行业以及业务场景
- 有较多逻辑增量同步的场景
- 有跨城市进行逻辑增量同步的场景
4、会导致什么问题?
- 每个逻辑增量解析链路都有1个进程负责, 当有较多逻辑增量同步链路时, 如果主节点的写操作较为频繁, 产生的WAL日志较多, 那么解析逻辑日志的CPU、IO压力也会较大, 影响主实例.
- 当有跨城市逻辑增量复制的需求时, 由于逻辑增量日志需要在事务结束时才能解析(为了保证原子性), 然后发送给下游, 容易产生较大延迟, 一般高于物理流复制的延迟.
原子性:
postgres=# SELECT * FROM pg_logical_slot_get_changes('test_slot', NULL, NULL, 'include-xids', '0');
lsn | xid | data
-----------+-----+--------------------------------------------------
0/16D30F8 | 691 | BEGIN
0/16D32A0 | 691 | table public.data: INSERT: id[int4]:2 data[text]:'arg'
0/16D32A0 | 691 | table public.data: INSERT: id[int4]:3 data[text]:'demo'
0/16D32A0 | 691 | COMMIT
0/16D32D8 | 692 | BEGIN
0/16D3398 | 692 | table public.data: DELETE: id[int4]:2
0/16D3398 | 692 | table public.data: DELETE: id[int4]:3
0/16D3398 | 692 | COMMIT
(8 rows)
5、业务上应该如何避免这个坑
- 暂时无解
6、业务上避免这个坑牺牲了什么, 会引入什么新的问题
7、数据库未来产品迭代如何修复这个坑
- 内核层支持standby slot, 通过feedback反馈给主库保留对应的catalog版本.