更新时间:2026-07-28 GMT+08:00
分享

分布式GTM-LITE容灾读

分布式GTM-LITE容灾读的实现原理与分布式备机读机制基本一致。

启用auto_csn_barrier参数后,系统进行barrier打点。在容灾读场景下,收集线程除持续向备DN节点收集barrier点的CSN外,还会对包括自身的每个CN节点发起请求,将每个CN视为独立分片参与校验。该机制要求至少存在一个CN节点能获取有效CSN值,最终计算出全局一致性的CSN保存至GTM中。

查询执行阶段,当所有备机节点满足一致性点时,系统优先选择级联备DN节点下发请求。级联备DN节点通过获取备机读的一致性点CSN值,基于csn-lsn info中查询对应LSN记录,最终将查询结果返回至CN节点。

分布式读机制依赖pgxc_node表维护的节点信息进行CN本地通信列表初始化。在容灾场景中,由于灾备集群的CN是主集群CN的备机,CN节点通过回放主集群pgxc_node表数据构建的,无法自主更新表中内容。因此主集群的pgxc_node表需额外记录灾备集群所有节点的静态信息。灾备集群的内部业务在访问系统表pgxc_node时,将通过GUC参数cluster_name(记录本集群的集群名)对表中的cluster_name字段进行过滤,筛选出本集群的节点信息。

特性约束

  • 容灾机制类约束:
    • 容灾集群不支持COPY TO操作,由于容灾集群的CN是备机,不能分配XID,COPY TO在CN上需要申请XID,故无法执行。执行时报错(ERROR: cannot assign TransactionIds during recovery)。
    • 分布式容灾单副本模式,不支持分布式读操作,可以使用维护模式进行连接执行本地查询。执行分布式查询时会出现报错(ERROR: Currently disaster cluster read is not supported)。
    • 如果主集群与容灾集群之间出现断连,那么从容灾集群上查询到的数据可能是旧数据。
    • GTM-Lite方案,在CN与DN连接时,需要根据当前全局一致性点,计算出对应分片中,可用的DN副本,以下场景可能出现报错:Current slice cannot select a normal standby for standby read, slice: 1
      • 同一副本中,如果出现两个DN回放快慢不一致,且更快的DN出现重启时。处理方法:此时全局一致性点不会再推进,等待回放慢的分片跟上全局一致性点,报错消失
      • 容灾映射刚完成构建,但还未收集到各个CN、DN的回放、回收信息时。处理方法:仅启动时间窗会短暂出现,等待几秒钟后不再出现。
      • 极致RTO模式下,如果出现不同分片回放差异很大,部分回放快的分片回收点超过全局一致性点时。报错后处理方法:等待业务高峰通过,各分片回放差异减小后,报错消失,如果仅有个别CN回放很慢,可以通过cm_ctl stop命令,手工停止CN规避此问题。
    • 当灾备集群出现CN剔除、CN加回、版本升级至506版本升级提交时,会对依赖pgxc_node表通信缓存产生影响,此时会触发内部的reload机制,reload期间(时间窗3s左右)内会出现以下已知报错:
      • node id %d is in pgxc_group but not in the handles, maybe rebuilding DisasterCache. 根因:缓存中pgxc_group与缓存中通信dn矩阵中记录的OID不匹配。
      • cache lookup failed for node %u. 根因:pgxc_node表中的oid,与缓存中记录的节点信息oid不匹配。
      • Cannot reload pool when in a transaction block. 根因:会话在事务中,检测发现pgxc_node更新,但此处事务不支持reload pool,此处会报错,但不会持续报错。
      • pooler: shmemNums does not match with usessNums, pgxc_node reload failed. 根因:通信缓存agent中记录的备机节点个数是旧的,但会话内存变量记录的备机节点个数,已经随pgxc_node表的更新而刷新了。
    • 因临时表、临时视图、临时序列和unlogged表,不产生Xlog,也不会同步到备机,所以备机读不支持查询此类对象,查询会报错:
      • ERROR: Temporary or unlogged table cannot be accessed on the standby.
  • 回放查询冲突类约束:
    • 主集群频繁vacuum、频繁DDL会影响日志回放速度,回放机制本身可能出现查询与回放冲突,回放日志时,如果持有冲突的会话,已经执行超过max_standby_streaming_delay的时间,会主动结束查询,返回错误:ERROR: canceling statement due to conflict with recovery / ERROR: terminating connection due to conflict with recovery。
  • 快照类约束:

    串并行回放容灾读:

    • 主集群做DDL操作,备集群回放DDL日志的时候,DDL在备集群上的某些节点中可能还没回放成功,校验快照失败,报错并结束查询(ERROR:current snapshot is invalid for this partition/relation)。
    • 主集群频繁vacuum会导致灾备集群查询的数据被提前清理掉等问题,读会话会检查快照是否大于DN最新的回放查询冲突点,不满足则说明此快照已经太旧了,不能读最新数据,主动报错并结束查询(ERROR: gtm csn small: gtm csn 123456789, lastReplayedConflictCSN 123456999 )。

    极致RTO容灾读:

    • 由于磁盘空间不足、修改GUC参数触发了强制回收,或发生过启停,或某一分片回放慢导致全局一致性点长时间推进缓慢,均会导致正常回放的CN/DN,由于本地历史版本不支持当前一致性点而不可读,报错结束查询(ERROR:snapshot csn is not in csn-lsn list)。
    • 系统表(relfilenode<16384)不会处理延迟DDL。在涉及系统表的TRUNCATE或DROP操作时,相关文件将被直接删除,包括极致RTO历史版本。在此类场景下,备机读操作可能因无法定位历史版本而报错:“ERROR: standby_read_buf can't find history version page/ERROR: block old version can not found”。
    • 段页式表,均不会进行延迟DDL处理,所以在段页式表触发TRUNCATE、DROP、REINDEX类的DDL操作时,备机回放会直接删除原数据文件,导致读段页式表0号页面报错。
  • 性能约束
    • 当主备集群查询所能占用到的资源相同时,对于并行回放下的Astore表:
      • 在主集群无写业务、备集群的日志都回放完成的场景下,对于select count(*) from xxx语句的负载,从时延的维度上观察,备集群的查询性能达到主集群的80%。
      • 在带有写业务的场景下:主集群和容灾集群的查询性能可能都会受业务影响而有波动,单次查询不保证容灾集群的性能达到主集群的80%;在无DDL的场景下,对于sysbench和TPCC的负载,从TPS、第95百分位数和平均时延的维度上观察,容灾集群的性能达到主集群的80%。
      • 如果有多个查询的主节点或备节点部署在同一个机器上,因这个机器的资源不足导致查询性能下降的情况下,则上面两个场景不成立。
      • 当发现前两个场景不成立时,建议检查容灾集群中各节点是否存在资源(CPU、内存、磁盘)受限的情况。
      • 由于容灾集群在并行回放下的Astore表不支持index only scan查询,因而对于select count(*) from xxx语句的负载可能需要读取更多的数据页面,建议通过调整shared_buffers参数进行缓存优化。
  • 兼容性场景约束

    当升级版本升级至506版本时,升级观察期期间,会使用旧版本映射方案处理容灾读通信列表,此时有相关约束:

    • 容灾集群上pgxc_node表的内容是同步自主集群的,所以容灾集群的CN会根据pgxc_node表中的node_oid与真实的节点信息做一层映射,但主备集群的node_name不是完全对应的,这会导致通过EXECUTEDIRECT ON语法实现的视图在容灾集群上的查询结果出现异常(结果重复或缺失),建议直接在对应的节点上查询。
    • 主备集群异构、CN数量不一致时,进行灾备集群读之前,应先查询出与主集群存在映射关系的灾备集群CN,再根据查询出的CN进行相关业务操作(查询方式:SELECT * FROM pgxc_disaster_read_status())。如果连接到和主集群不存在映射关系的CN,由于此CN自身的一致性点不参与全局一致性点的计算,可能会出现连接报错(ERROR: cn data invisible: local csn 123456789, gtm snapshotcsn 123456999)。
    • 如果使用JDBC连接容灾集群,且开启了负载均衡功能,那么查询请求会发送到主集群上,导致查询性能受到影响。
    • 重启cn容灾搭建完成后,因容灾读本集群拓扑节点信息,依赖pgxc_node表回放后内部映射机制的构建。在容灾映射构建完成前,读请求会出现报错:Not support disaster read before init. 容灾集群关系搭建完成,灾备集群正常启动后,10s左右(主集群、灾备集群之间无RTO差距)此读报错消失。
    • 容灾集群由于pgxc_node表,是通过回放记录主集群的拓扑信息,如果出现,1)双集群集群间倒换,2)1:N主备集群部署场景下,主备集群倒换,3)主集群节点替换、CN剔除等,主集群拓扑结构变更导致灾备pgxc_node表被动更新时,由于分布式查询CN中使用的部分系统缓存,通过pgxc_node表中的记录oid作为key,当线程读到新的pgxc_node表信息,但系统缓存还未来得及更新时,此时间窗(3s左右)内会出现以下已知报错:
      • node id %d is in pgxc_group but not in the handles, maybe rebuilding DisasterCache. 根因:缓存中pgxc_group与缓存中通信dn矩阵中记录的OID不匹配。
      • cache lookup failed for node %u. 根因:pgxc_node表中的oid,与缓存中记录的节点信息oid不匹配。
      • Cannot reload pool when in a transaction block. 根因:会话在事务中,检测发现pgxc_node更新,但此处事务不支持reload pool,此处会报错,但不会持续报错。
      • pooler: shmemNums does not match with usessNums, pgxc_node reload failed. 根因:通信缓存agent中记录的备机节点个数是旧的,但会话内存变量记录的备机节点个数,已经随pgxc_node表的更新而刷新了。

相关文档