PostgreSQL逻辑复制解密原理解析


Posted in PostgreSQL onSeptember 23, 2022

在数字化时代的今天,我们都认同数据会创造价值。为了最大化数据的价值,我们不停的建立着数据迁移的管道,从同构到异构,从关系型到非关系型,从云下到云上,从数仓到数据湖,试图在各种场景挖掘数据的价值。而在这纵横交错的数据网络中,逻辑复制扮演着及其重要的角色。让我们将视角从复杂的网络拉回其中的一个端点,从PostgreSQL出发,对其逻辑复制的原理进行解密。

在数字化时代的今天,我们都认同数据会创造价值。为了最大化数据的价值,我们不停的建立着数据迁移的管道,从同构到异构,从关系型到非关系型,从云下到云上,从数仓到数据湖,试图在各种场景挖掘数据的价值。而在这纵横交错的数据网络中,逻辑复制扮演着及其重要的角色。

让我们将视角从复杂的网络拉回其中的一个端点,从PostgreSQL出发,对其逻辑复制的原理进行解密。

1 概念与原理

逻辑复制,是基于复制标识复制数据及其变化的一种方法。区别于物理复制对页面操作的描述,逻辑复制是对事务及数据元组的一种描述。

PostgreSQL逻辑复制解密原理解析

图-WAL数据流示例

如图所示,物理复制的数据流是对tablespace/database/filenode文件的块进行操作,而逻辑复制的内容是对元组进行描述。

接下来我们来看逻辑复制中的几个概念:

复制槽

复制槽是记录复制状态的一组信息。由于WAL(预写式日志)文件在数据真正落盘后会删除,复制槽会防止过早清理逻辑复制解析所需的WAL日志。在逻辑复制中,每个插槽从单个数据库流式传输一系列更改,创建复制槽需要指定其使用的输出插件,同时创建复制槽时会提供一个快照。

输出插件

输出插件负责将WAL日志解码为可读的格式,常用的插件用test_decoding(多用来测试),pgoutput(默认使用),wal2json(输出为json)。PostgreSQL定义了一系列回调函数,我们除了使用上述插件,可以通过回调函数编写自己的输出插件。

PostgreSQL逻辑复制解密原理解析

图-复制槽数据流

复制协议与消息

通过复制协议,我们可以从源端获取WAL数据流。例如通过PSQL工具建议复制连接

psql "dbname=postgres replication=database"

开启流式传输WAL

START_REPLICATION[ SLOT slot_name] [ PHYSICAL] XXX/XXX[ TIMELINE tli]

无论是物理复制,还是逻辑复制,使用PostgreSQL的发布订阅或者pg_basebackup搭建流复制,都是通过复制协议与定义的消息进行交互(物理复制和逻辑复制数据流内容不同)

PostgreSQL逻辑复制解密原理解析

图- WAL数据流消息类型

PostgreSQL逻辑复制解密原理解析

图-逻辑复制中的XLogData消息

工作流程

当我们了解了概念之后,来看一下整个解析的工作流程。由于WAL文件里一个事务的内容并不一定是连续的,所以需要通过Reorder后放在buffer中,根据事务ID组织成一条消息,COMMIT后发送给输出插件,输出插件解析后将消息流发送给目标端。

PostgreSQL逻辑复制解密原理解析

图-逻辑解析工作流程

2 问题与演进

当我们掌握了逻辑复制的原理,计划使用其构建我们的数据迁移应用之前,我们还有一些问题并没有解决。让我们来一起看看是什么亟待解决的问题,以及我们如何进行处理。

问题一:Failover slot

为了高可用性,数据库至少会存在一主一备的架构,当主库故障进行高可用切换时,备库却没有相应的复制槽信息,也就是缺少failover slot。这是由于保存slot信息的物理文件,未同步至备库。那么我们如何手动创建一个faliover slot呢?

1. 主库创建复制槽,检查备库wal文件是否连续

2. 复制包含slot信息的物理文件至备库,在pg_repslot目录下

3. 备库重启,重启后才可以看到复制槽信息,原因是读取slot物理文件的函数StartupReplicationSlots只会在postmaster进程启动时调用。

4. 定期查询主库slot状态,使用pg_replication_slot_advance函数推进备库复制槽

自此,我们在备库上也有了相应的信息,手动实现了failover slot。PostgreSQL生态中著名的高可用软件Patroni也是以这种方式进行了实现,区别只是在Patroni查询主库slot状态时将信息写入了DCS中,备库拿到DCS中的位点信息进行推进。

问题二:DDL同步

原生的逻辑复制不支持解析DDL语句,我们可以使用事件触发器来进行处理。

1. 使用事件触发器感知表结构变更,记录到DDL_RECORD表中,并将该表通过逻辑复制进行发布。

2. 接收端获取到该表的数据变更,即可处理为相应DDL语句进行执行。

PostgreSQL逻辑复制解密原理解析

图-事件触发器实现DDL同步

问题三: 双向同步

当数据迁移涉及双向同步的管道时,例如想实现双主双写,对数据库同一对象进行操作,就会出现WAL循环。

PostgreSQL逻辑复制解密原理解析

图-相同表双向同步导致数据循环

部分DTS应用为了解决这个问题会创建辅助表,在事务中先对辅助表进行操作,通过解析到对辅助表的操作而得知该记录是又DTS应用插入,从而过滤该事务,不再循环解析。PostgreSQL对事务提供了Origin记录,无须辅助表,通过pg_replication_origin_session_setup函数或者发布订阅中的replorigin_create即可指定Origin ID。

指定Origin ID后,我们除了可以解析后通过DTS应用进行过滤,还也可以通过解析插件中的FilterByOriginCB回调函数在解析过程中过滤,这种方式减少了数据传输,效率更高。

PostgreSQL逻辑复制解密原理解析

图-test_decoding中OriginFilter函数DEMO

其他问题:

除了以上三个问题,还有一些使用的问题或限制。这里列出了一些,不再展开,仅简要说明。

Toast处理:对于toast值(消息格式中可以判断),我们在处理时一般使用占位符进行处理,接收端接收到占位符就不对这一列进行处理,虽然有些麻烦,但这也是在和传输toast值的方案中权衡的结果。

心跳表:由于复制槽记录的XMIN是全局的,当我们发布的表一直没有更新时,XMIN没有推进导致WAL积压,我们可以创建一张心跳表,周期性写入数据并发布,使XMIN进行推进。

大事务延迟: 根据前文提到的工作流程我们可以知道默认事务在COMMIT后才会进行解析,这对于大事务来说势必会导致延迟,PG14版本提供了streamin模式进行解析,即事务进行中进行解析并发送至接收端。

3 应用与实践

前两节我们从原理及问题的角度对PostgreSQL进行了解密,接下来我们看如何通过我们掌握的逻辑复制原理,进行数据迁移的应用与实践。

全量与增量同步

在真实的数据迁移场景中,大部分都是全量和增量都要同步的场景,并且我们打通了数据传输的通道后,也对这条通道的安全,效率,以及功能的扩展,例如清洗,脱敏等ETL能力提出了新的要求。我们先来看一下如果实现全量与增量的同步。

PostgreSQL逻辑复制解密原理解析

图-数据流向示意图

主要流程包括:

1. 创建复制槽并导出快照

2. 根据快照进行全量数据迁移

3. 根据复制槽进行增量数据的迁移

我们使用了PG数据库或者消息队列MQ作为数据代理,全量与增量解析可以同时进行,当全量数据处理完毕后,状态机通知增量处理程序进行增量发布。而对于代理中的数据,可以在解析后进行预处理。

自建实例迁移上云实践

最后和大家分享一个自建实例迁移上云的实践,该案例是将自建的PG10版本实例迁移至京东云上的RDS PG 11版本,通过对增量数据的回流以及数据校验保证了数据安全与业务平稳切换。

PostgreSQL逻辑复制解密原理解析

图-数据迁移上云

DTS应用主要分为如下几个阶段:

1. 数据检查阶段: 检查主键,权限,配置

2. 数据迁移阶段: 结构,存量,增量数据迁移,监控迁移状态

3. 应用迁移阶段: 切换域名,引入流量

4. 回滚阶段: 增量数据回流,若出现问题可快速回滚。

到此这篇关于PostgreSQL逻辑复制解密原理解析的文章就介绍到这了,更多相关PostgreSQL逻辑复制解密内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

PostgreSQL 相关文章推荐
如何使用PostgreSQL进行中文全文检索
May 27 PostgreSQL
postgres之jsonb属性的使用操作
Jun 23 PostgreSQL
通过Qt连接OpenGauss数据库的详细教程
Jun 23 PostgreSQL
PostgreSQL解析URL的方法
Aug 02 PostgreSQL
关于PostgreSQL JSONB的匹配和交集问题
Sep 14 PostgreSQL
PostgreSQL并行计算算法及参数强制并行度设置方法
Apr 06 PostgreSQL
PostgreSQL 插入INSERT、删除DELETE、更新UPDATE、事务transaction
Apr 12 PostgreSQL
PostgreSQL数据库去除重复数据和运算符的基本查询操作
Apr 12 PostgreSQL
PostgreSQL基于pgrouting的路径规划处理方法
Apr 18 PostgreSQL
PostgreSQL常用字符串分割函数整理汇总
Jul 07 #PostgreSQL
PostgreSQL怎么创建分区表详解
Jun 25 #PostgreSQL
PostgreSQL出现死锁该如何解决
PostgreSQL基于pgrouting的路径规划处理方法
Apr 18 #PostgreSQL
postgreSQL数据库基础知识介绍
PostgreSQL数据库去除重复数据和运算符的基本查询操作
PostgreSQL聚合函数介绍以及分组和排序
You might like
简单的php文件上传(实例)
2013/10/27 PHP
PHP网页游戏学习之Xnova(ogame)源码解读(七)
2014/06/23 PHP
jquery+php实现导出datatables插件数据到excel的方法
2015/07/06 PHP
Laravel用户授权系统的使用方法示例
2018/09/16 PHP
php中file_get_contents()函数用法实例
2019/02/21 PHP
Mootools 1.2教程 Tooltips
2009/09/15 Javascript
jquery中的mouseleave和mouseout的区别 模仿下拉框效果
2012/02/07 Javascript
jquery $.each() 使用小探
2013/08/23 Javascript
js jquery分别实现动态的文件上传操作按钮的添加和删除
2014/01/13 Javascript
javascript 中that的含义示例介绍
2014/05/14 Javascript
JavaScript中自定义事件用法分析
2014/12/23 Javascript
详解jQuery停止动画——stop()方法的使用
2016/12/14 Javascript
jQuery html表格排序插件tablesorter使用方法详解
2017/02/10 Javascript
详解如何使用Node.js编写命令工具——以vue-cli为例
2017/06/29 Javascript
webpack external模块的具体使用
2018/03/10 Javascript
React路由管理之React Router总结
2018/05/10 Javascript
在vue中给列表中的奇数行添加class的实现方法
2018/09/05 Javascript
vue 右键菜单插件 简单、可扩展、样式自定义的右键菜单
2018/11/29 Javascript
vue项目中引入vue-datepicker插件的详解
2019/05/14 Javascript
javascript实现商品图片放大镜
2019/11/28 Javascript
简单了解Vue + ElementUI后台管理模板
2020/04/07 Javascript
vue中提示$index is not defined错误的解决方式
2020/09/02 Javascript
unittest+coverage单元测试代码覆盖操作实例详解
2018/04/04 Python
django 多对多表的创建和插入代码实现
2019/09/09 Python
使用python实现时间序列白噪声检验方式
2020/06/03 Python
css3闪亮进度条效果实现思路及代码
2013/04/17 HTML / CSS
html5之Canvas路径绘图、坐标变换应用实例
2012/12/26 HTML / CSS
Otticanet英国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/02/10 全球购物
Ray-Ban雷朋瑞典官方网站:全球领先的太阳眼镜品牌
2019/08/22 全球购物
北美最大的零售退货翻新商:VIP Outlet
2019/11/21 全球购物
人力资源作业细则
2014/03/03 职场文书
同学会主持词
2014/03/18 职场文书
闭幕式主持词
2014/04/02 职场文书
幼儿园运动会口号
2014/06/07 职场文书
农村文化建设标语
2014/10/07 职场文书
公务员年度考核个人总结
2015/02/12 职场文书