逻辑解码概述
功能描述
逻辑解码为逻辑复制提供事务解码的基础能力,GaussDB可以使用SQL函数接口进行逻辑解码。此方法调用方便,不需使用工具,对接外部工具接口也比较清晰,不需要额外适配。
由于逻辑日志是以事务为单位的,在事务提交后才能输出,且逻辑解码是由用户驱动的。因此,为了防止事务开始时的xlog被系统回收,或所需的事务信息被VACUUM回收,GaussDB新增了逻辑复制槽,用于阻塞xlog的回收。
一个逻辑复制槽表示一个更改流,这些更改可以在其他数据库上以它们在原数据库上产生的顺序重新执行。每个逻辑复制槽都由其对应逻辑日志的获取者维护。如果处于流式解码中的逻辑复制槽所在库不存在业务,则该复制槽会依照其他库的日志位置来推进。活跃状态的LSN序逻辑复制槽在处理到活跃事务快照日志时可以根据当前日志的LSN推进复制槽;活跃状态的CSN序逻辑复制槽在处理到虚拟事务日志时可以根据当前日志的CSN推进复制槽。
前提条件
- 逻辑日志目前从CN或DN中抽取,如果进行逻辑复制,应使用SSL连接,因此需要保证相应节点上的GUC参数SSL设置为on。
为避免安全风险,请保证启用SSL连接。
- 设置GUC参数wal_level为logical。
- 设置GUC参数max_replication_slots>=每个节点所需的(物理流复制槽数+备份槽数+逻辑复制槽数)。
关于逻辑复制槽数,请按如下规则考虑:
- 一个逻辑复制槽只能解码一个Database的修改,如果需要解码多个Database,则需要创建多个逻辑复制槽。
- 如果需要多路逻辑复制同步给多个目标数据库,在源端数据库需要创建多个逻辑复制槽,每个逻辑复制槽对应一条逻辑复制链路。
- 同一个CN节点上最多支持同时开启10个分布式CN强一致解码任务,同一个DN节点上最多支持同时开启20个解码任务。
- 用户需要通过DN端口连接数据库,才可以直接使用SQL函数接口进行逻辑解码操作,相关操作请参见使用SQL函数接口进行逻辑解码。如果使用CN端口连接数据库,则需要通过EXECUTE DIRECT ON (datanode_name) 'statement'语句来执行SQL函数。
- 仅限初始用户或拥有REPLICATION权限的用户进行操作。三权分立关闭时数据库管理员可进行逻辑复制操作,三权分立开启时不允许数据库管理员进行逻辑复制操作。
注意事项
- 不支持数据页复制的DML解码。
- 逻辑复制不支持集群在线扩容。在线扩容前,需要删除已存在的逻辑复制槽,扩容完成后重新创建。
- 单条元组大小不超过1GB,考虑解码结果可能大于插入数据,因此建议单条元组大小不超过500MB。
- GaussDB支持解码的数据类型为:INTEGER、BIGINT、SMALLINT、TINYINT、SERIAL、SMALLSERIAL、BIGSERIAL、FLOAT、DOUBLE PRECISION、BOOLEAN、BIT(n)、BIT VARYING(n)、DATE、TIME[WITHOUT TIME ZONE]、TIMESTAMP[WITHOUT TIME ZONE]、CHAR(n)、VARCHAR(n)、TEXT、CLOB(解码成TEXT格式)。
- 非M兼容库的浮点型数据、M兼容库的不带标度的float类型,解码结果显示精度extra_float_digits配置为3(该参数的含义参见GUC参数float_shortest_precision的具体信息)。
- 不支持解码PUBLIC SCHEMA的DDL操作。
- 支持M-Compatibility模式数据库的DML、DDL逻辑解码,解码数据类型如下:
- 整型:TINYINT(M)、SMALLINT(M)、MEDIUMINT(M)、BIGINT(M)、INT(M)/INTEGER、BOOL/BOOLEAN。
- 浮点型:FLOAT(M,D)、DOUBLE(M,D)。
- 定点型:DECIMAL(M,D)、NUMERIC(M,N)。
- BIT类型:BIT。
- 字符串二进制类型:CHAR(N)、VARCHAR(N)、BINARY、VARBINARY。
- 文本类型:TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT。
- 日期类型:DATE、TIME、DATETIME、TIMESTAMP、YEAR。
- 大对象类型:TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB。
- 数据类型属性:UNSIGNED、ZEROFILL。
- M-Compatibility模式数据库,逻辑解码特殊约束如下:
- CREATE TABLE、ALTER TABLE、DROP TABLE等语法中的[partition_options]、ENGINE、ROW_FORMAT、algorithm_option、lock_option等选项在语法中无实际作用,此类语法不进行解码输出。
- 对于ALTER SCHEMA、CREATE SCHEMA、DROP SCHEMA、ALTER DATABASE、CREATE DATABASE、DROP DATABASE语法中,因为M-Compatibility模式数据库下,DATABASE与Schema等价,所以ALTER DATABASE、CREATE DATABASE、DROP DATABASE会被解码为ALTER SCHEMA、CREATE SCHEMA、DROP SCHEMA。
- 对于写法不同的字符设置语法,比如CHARACTER SET、CHAR SET、CHARSET都会被解码为CHARACTER SET。
- 对于ALTER TABLE tbl_name DROP {INDEX | KEY} index_name语法,逻辑解码结果为DROP INDEX;对于删除主键 ALTER TABLE tbl_name DROP {primary key | {index | key} index_name} 语法会被解码为 ALTER TABLE tbl_name DROP CONSTRAINT index_name。
- 对于ALTER TABLE tbl_name ADD INDEX语法,逻辑解码结果为CREATE INDEX。
- 在解码DML语句时,涉及插入时间类型带精度的(time、timestamp、datetime),按照最大精度6解码。
- 对于支持二进制输入的数据类型(BINARY、VARBINARY、TINYBLOB、BLOB、MEDIUMBLOB、LONGBLOB),如果数据中包括'\0'会发生截断,仅支持并行解码BINARY格式输出(即解码任务参数decode-style='b'),串行解码、函数解码以及并行json、text格式输出均会发生截断。
- REPLACE语法为DML语法,REPLACE会被解码为对数据实际的操作,比如INSERT或DELETE+INSERT(存在主键或唯一键冲突)。
- COPY语法/LOAD语法为DML语法,会被解码为对数据实际的操作,比如多条INSERT。
- 逻辑复制槽名称必须小于64个字符,使用SQL函数创建或使用复制槽时,复制槽名称仅支持小写字母、数字以及_、?、-和.字符,且不支持.或..单独作为复制槽名称。调用JDBC API创建或使用复制槽时,复制槽名称仅支持小写字母、数字以及_字符(可以输入大写字母,但在内部会将其被转成小写字母进行处理,例如输入名称为MSLOT,实际名称是mslot)。
- 对多库的解码需要分别在库内创建流复制槽并开始解码,每个库的解码都需要单独扫描一遍日志。
- 不支持强切,强切后需要重新全量导出数据。
- 备机解码时,switchover和failover可能出现解码数据变多,需用户手动过滤。Quorum协议下,switchover和failover选择升主的备机,需要与当前主机日志同步。
- 备机解码时,如果需要删除数据库,需要业务保证数据完成迁移后,主机再删除逻辑复制槽对应的数据库。当前没有强制要求删除数据库之前一定要先删除库上的逻辑复制槽,可能出现当前库备机解码还未完成,主机删除数据库的情况。如果出现这种情况,当备机回放到删除数据库的动作,备机即使未完成当前库的所有解码任务,也会退出解码,如果再次重连,备机解码会因为已经删除数据库而无法启动,造成解码任务受损。
- 只支持CN和主DN创建删除复制槽。当删除的复制槽为最后一个复制槽时,删除完成后会产生告警"replicationSlotMinLSN is INVALID_WAL_REC_PTR!!!"和"replicationSlotMaxLSN is INVALID_WAL_REC_PTR!!!"。
- 不允许主备DN、多个备DN同时使用同一个复制槽解码,否则会产生数据不一致或者其他异常错误的情况。
- 数据库故障重启或逻辑复制进程重启后,解码数据可能存在重复,用户需手动过滤。
- 计算机内核故障后,解码可能存在乱码,需手动或自动过滤。
- 请确保在创建逻辑复制槽过程中未启动长事务,启动长事务会阻塞逻辑复制槽的创建。
- 不支持全局临时表的DML解码。
- 不支持本地临时表的DML解码。
- SELECT INTO语句会解码创建目标表的DDL操作,数据插入的DML操作不解码。
- 为解析某个astore表的UPDATE和DELETE语句,需为此表配置REPLICA IDENTITY属性,在此表无主键时需要配置为FULL,具体配置方式请参考《开发指南》中“SQL参考 > SQL语法 > A > ALTER TABLE”章节中“REPLICA IDENTITY { DEFAULT | USING INDEX index_name | FULL | NOTHING }”字段。
- 禁止在使用逻辑复制槽时在其他节点对该复制槽进行操作,删除复制槽的操作需在该复制槽停止解码后执行。
- 基于目标库可能需要源库的系统状态信息考虑,逻辑解码仅自动过滤模式'pg_catalog'和'pg_toast'下OID小于16384的系统表的逻辑日志。若目标库不需要复制其他相关系统表的内容,逻辑日志回放过程中需要对相关系统表进行过滤。
- 在开启逻辑复制的场景下,如需创建包含系统列的主键索引,必须将该表的REPLICA IDENTITY属性设置为FULL或是使用USING INDEX指定不包含系统列的、唯一的、非局部的、不可延迟的、仅包括标记为NOT NULL列的索引。
- 对于缩容或升级前已存在的复制表场景,需要对复制表手动配置logical_repl_node属性或RESET为默认值,配置方式请参考《开发指南》中“SQL参考 > SQL语法 > A > ALTER TABLE”章节中“storage_parameter”参数的使用说明,以及“logical_repl_node”属性相关说明。
- 若一个事务的子事务过多导致落盘文件过多,退出解码时需执行SQL函数pg_terminate_backend(逻辑解码的walsender线程id)来手动停止解码,而且退出时延增加约为1分钟/30万个子事务。因此在开启逻辑解码时,若一个事务的子事务数量达到5万时,会打印一条WARNING日志。
- 当逻辑复制槽处于非活跃状态,且设置GUC参数enable_xlog_prune=on、enable_logicalrepl_xlog_prune=on、max_size_for_xlog_retention为非零值,且备份槽或逻辑复制槽导致保留日志段数已超过GUC参数wal_keep_segments,同时其他复制槽并未导致更多的保留日志段数时,如果max_size_for_xlog_retention大于0且当前逻辑复制槽导致保留日志的段数(每段日志大小为16MB)超过max_size_for_xlog_retention,或者max_size_for_xlog_retention小于0且磁盘使用率达到(-max_size_for_xlog_retention)/100,当前逻辑复制槽会强制失效,其restart_lsn将被设置为7FFFFFFF/FFFFFFFF。该状态的逻辑复制槽不参与阻塞日志回收或系统表历史版本的回收,但仍占用复制槽的限制数量,需要手动删除。
- 备机解码启动后,向主机发送复制槽推进指令后会占用主机上对应的逻辑复制槽(即标识为活跃状态)。在此之前主机上对应逻辑复制槽为非活跃状态,此状态下如果满足逻辑复制槽强制失效条件则会被标记为失效(即restart_lsn将被设置为7FFFFFFF/FFFFFFFF),备机将无法推进主机复制槽,且备机回放完成复制槽失效日志后当前复制槽的备机解码断开后将无法重连。
- 不活跃的逻辑复制槽将阻塞WAL日志回收和系统表元组历史版本清理,导致磁盘日志堆积和系统表扫描性能下降,因此不再使用的逻辑复制槽请及时清理。需要特别注意,在升级提交之前观察期内使用DN扩展IP连接DN创建的逻辑复制槽,在升级回滚之前务必手动清理,否则随着DN扩展IP特性回滚无法直连DN清理。
- 分布式强一致逻辑解码(连接CN解码)仅支持GTM-Lite分布式部署及流式解码,不支持CN连接备DN进行解码、SQL逻辑解码函数、在线扩容、全局索引。
- 针对分布式强一致逻辑解码(连接CN解码)功能,CN高可用由业务负责切换。
- CN上的CSN序逻辑复制槽仅起到占位作用,不随着逻辑解码的进行而推进,同时也不会阻塞日志回收。
- 通过协议连接CN创建逻辑复制槽仅支持CSN序复制槽,通过协议连接DN创建逻辑复制槽仅支持LSN序复制槽。
- 针对分布式解码,对于故障报错或者手动停止解码客户端等场景,需等待15秒再次重试解码,如有复制槽占用则需通过执行SQL函数pg_terminate_backend(占用该复制槽线程id)来手动解除复制槽占用。
- 在CN上创建复制槽失败报错后,需要在CN上进行复制槽删除操作,然后在CN上重新创建复制槽。
- 在CN上删除逻辑复制槽时,若为LSN序逻辑复制槽,则仅删除当前节点复制槽,其他节点同名复制槽不受影响;否则只要其他节点有残留同名CSN序逻辑复制槽,执行删除时不会因为某些节点不存在复制槽而报错,同时所有节点的同名复制槽会被成功删除;如果任何节点均不存在该复制槽,则报错。
- 在CN上创建CSN序逻辑复制槽时,某些节点如残留同名LSN序逻辑复制槽,需在这些节点执行删除残留复制槽的操作。否则会在除当前CN节点外,其他不存在同名复制槽的CN和主DN节点上创建CSN序逻辑复制槽。
- 如果当前CN节点残留LSN序逻辑复制槽,同时其他某些节点上残留同名CSN序逻辑复制槽,则在当前CN节点上执行删除复制槽操作仅会删除本地LSN序逻辑复制槽,待删除完成再次执行删除操作方可删除其他节点的同名复制槽。
- 解码使用JSON格式输出时不支持数据列包含特殊字符(如'\0'空字符),解码输出列内容将出现被截断现象。
- 不支持无日志表的DML解码。
- 执行备份恢复操作时,实例恢复完成后会清理所有的逻辑复制槽,如有需要须重新建槽。
- 删除复制槽需要在删除数据库之前执行,当逻辑复制槽所在数据库被删除后,这些复制槽变为不可用状态,需要用户手动删除,否则会阻塞wal日志回收。
- 当同一事务产生大量需要落盘的子事务时,同时打开的文件句柄可能会超限,需将GUC参数max_files_per_process配置成大于子事务数量上限的两倍。
- 不支持全局二级索引,不支持分布列修改的DML解码。
- 容灾集群的备集群不支持通过SQL系统函数或工具进行逻辑解码。
- 不支持账本数据库功能,当前版本如果开启解码任务的数据库中有关于账本数据库的DML操作,则解码结果中会包含hash列,从而导致回放失败。
- 扩容场景下,若集群中创建有逻辑复制槽,会导致扩容失败,因此扩容前需要删除当前集群中已存在的逻辑复制槽。
- 不支持主键、外键、唯一约束中的信息约束(如not enforced等)选项,如果出现信息约束,则涉及信息约束的约束不解码,其他DDL照常解码。例如:“create table test(a int primary key not enforced);”语句会被解码为“create table test(a int);”。
- 使用CREATE TABLE语法创建表时不支持MURMURHASH选项的解码,若有MURMURHASH选项,将不解码该DDL语句。
- 仅支持wal_level=logical的WAL日志解码,对于非logical的日志,串行解码(包括函数解码)输出结果中没有对应的值和类型,并行解码不输出其逻辑日志。
- 逻辑解码支持如下Xlog类型的DML:
- Astore: insert、delete、update、multi-insert。
- Ustore: insert、delete、update、multi-insert。
- wal_level值为logical的情况下,Xlog日志数据量相比hot_standby级别有一定膨胀。例如:在TPCC场景下,Astore的Xlog膨胀率约为11%,Ustore的Xlog膨胀率约为110%。
- 大小写不敏感数据库解码时,无论创建表名或用户名时使用的是大写还是小写,输入解码选项白名单(white-table-list)或黑名单(exclude-users)中的表名或用户名时都须使用小写。
- 逻辑复制槽会保护未解析XLOG对应版本的系统表记录不被过早清理。当逻辑复制槽处于不活跃状态或者客户端消费过慢时,可能会对业务造成以下影响:(1)如果业务中有大量的DDL,则会导致系统表历史版本过多,影响SQL命令执行效率;(2)由于GaussDB数据页面管理的约束:同一页面中无法存放xid差值超过2^32的两条记录。当系统表历史版本过多时,可能会阻塞DDL和DML等业务操作无法正常执行(错误码:GAUSS-21297)。
处理措施:(1)及时清理不再使用的逻辑复制槽;(2)如果逻辑复制槽推进过慢,请参考《故障处理》文档“常见故障界定与处理 -> 逻辑解码相关故障 -> 逻辑复制槽异常/逻辑解码性能慢”章节进行处理;(3)如果措施(2)未解决推进慢问题,则需要删除复制槽,重建逻辑解码任务。
SQL函数解码性能
- 在Benchmarksql-5.0的100warehouse场景下,采用pg_logical_slot_get_changes时:
- 单次解码数据量4K行(对应约5MB~10MB日志),解码性能0.3MB/s~0.5MB/s。
- 单次解码数据量32K行(对应约40MB~80MB日志),解码性能3MB/s~5MB/s。
- 单次解码数据量256K行(对应约320MB~640MB日志),解码性能3MB/s~5MB/s。
- 单次解码数据量再增大,解码性能无明显提升。
如果采用pg_logical_slot_peek_changes + pg_replication_slot_advance方式,解码性能相比采用pg_logical_slot_get_changes时要下降30%~50%。
- 在Benchmarksql-5.0的100warehouse场景下,采用pg_logical_get_area_changes时:
- 单次解码数据量4K行(对应约5MB~10MB日志),解码性能0.3MB/s~0.5MB/s。
- 单次解码数据量32K行(对应约40MB~80MB日志),解码性能3MB/s~5MB/s。
- 单次解码数据量256K行(对应约320MB~640MB日志),解码性能3MB/s~5MB/s。
- 单次解码数据量再增大,解码性能无明显提升。
- 在Benchmarksql-5.0的100warehouse场景下,采用pg_logical_slot_get_binary_changes时:
- 单次解码数据量4K行(对应约5MB~10MB日志),解码性能0.3MB/s~0.5MB/s。
- 单次解码数据量32K行(对应约40MB~80MB日志),解码性能2MB/s~3MB/s。
- 单次解码数据量256K行(对应约320MB~640MB日志),解码性能2MB/s~3MB/s。
- 单次解码数据量再增大,解码性能无明显提升。
如果采用pg_logical_slot_peek_binary_changes + pg_replication_slot_advance方式,解码性能相比采用pg_logical_slot_get_binary_changes时要下降30%~50%。
流式解码性能
在并行解码的标准场景下(16核CPU、内存128GB、网络带宽 > 200MBps、表的列数为10~100、单行数据量0.1KB~1KB、DML操作以insert为主、不涉及落盘事务即单个事务中语句数量小于4096、parallel-decode-num为8、解码格式为't'且开启批量发送功能),连接DN解码性能(以Xlog消耗量为标准)不低于100MBps,连接CN解码性能不低于80MBps。为保证解码性能达标以及尽量降低对业务的影响,一台备机上应尽量仅建立一个并行解码连接,保证CPU、内存、带宽资源充足。