关于大数据:Tapdata-肖贝贝实时数据引擎系列六从-PostgreSQL-实时数据集成看增量数据缓存层的必要性

31次阅读

共计 5844 个字符,预计需要花费 15 分钟才能阅读完成。

摘要:对于 PostgreSQL 的实时数据采集,业界常常遇到了包含:对源库性能 / 存储影响较大, 采集性能受限, 工夫回退从新同步不反对, 数据类型较简单等等问题。Tapdata 在解决 PostgreSQL 增量复制问题过程中,取得了一些不错的教训和思考,本文将分享 Tapdata 自研的 TAP-CDC-CACHE,和其余几种市面常见的解决方案的劣势和个性。

前言
TAPDATA 的数据复制产品里, 提供了对于 PostgreSQL 的实时数据采集性能, 在客户落地应用时, 遇到了包含 对源库性能 / 存储影响较大, 采集性能受限, 工夫回退从新同步不反对, 数据类型较简单 等等问题, 在解决这些问题的过程中, 咱们逐步对增量事件应该具备一个缓存中间件有了清晰的意识, 并在之后的工夫里做了相应的实现

本文从咱们在解决 PostgreSQL 增量复制的问题登程, 在一步步寻找解决方案的过程中, 分享一下咱们最终解决方案的过程和对这个问题的一些思考
PG 增量数据捕捉的几种常见计划
万变不离其宗, PostgreSQL 捕捉增量事件的原理与 Mysql, MongoDB 等数据库相似, 其本质都是基于事务日志进行回放, 这种日志在 PG 里被称为 Write-Ahead Logging(WAL), 通过对 WAL 的解析, 能够失去数据库的逻辑事件变更, 上游的各种消费者能够在这个根底上实现数据复制, 流计算等等各种需要

在具体的实现上, 通常有以下三种技术选型
基于复制槽的解码与查问
针对开发者进行数据逻辑复制的需要, PostgreSQL 凋谢了对于 WAL 的订阅接口, 开发者须要创立一个名为复制槽的构造, 并指定其解码插件, 之后只须要轮询这个复制槽, 即可获取最新的以事务为最小粒度的数据变更

常见的解码器有 decoderbufs, wal2json, pgoutput 等等, TAPDATA 反对的插件, 其对应的数据库版本与特点如下:

除此之外, 还有一些其余插件, 比方: decoding-json, decoder_json, jsoncdc, wal2mongo, postgres-decoderbufs, Bottled Water, osm-logical, pglogical, transicator 等等各式各样的输入格局, 用户能够依照本人的需要抉择适合的插件, 也能够本人开发对应的解码器

以 wal2json 为例, 具体的应用命令如下:

## 创立一个 slot, 命名为 tapdata, 用来接管 CDC 事件, 并应用 wal2json 解析
select * from pg_create_logical_replication_slot('tapdata', 'wal2json');

## 查看 slot 根本信息
select * from pg_replication_slots where slot_name='tapdata';

## 从 slot 读取数据, 并清理读过的数据
## 办法反对的参数的为:
## 1. slot 名字, 必选
## 2. 一个 lsn 地位, 必选, 读取到这个地位为止, 剩下的此次查问不返回
## 3. 一个 limit 数字 n, 必选, 最多读取 n 条为止, 剩下的此次查问不返回, 与 lsn 满足任意一条即进行读取
## 4. options, 可选, 管制一些输入的数据内容, 具体能够查看: https://pgpedia.info/p/pg_logical_slot_get_changes.html
select * from pg_logical_slot_get_changes('tapdata', NULL, NULL)

## 从 slot 读取数据, 保留读过的数据, 参数与 pg_logical_slot_get_changes 完全一致
select * from pg_logical_slot_peek_changes('tapdata', NULL, NULL)

## select 反对应用 xid, lsn 等条件进行过滤, 比方限度返回的条目数为 10, 并且 lsn > '1/47CB8450', 可如下写
select * from pg_logical_slot_peek_changes('tapdata', NULL, NULL) where lsn > '1/47CB8450' limit 10

## 因为 pg_logical_slot_peek_changes 不清理数据, 在须要清理 lsn 时, 能够应用 pg_replication_slot_advance
## 将 lsn 推动到指定地位, 并清理之前的记录
select * from pg_replication_slot_advance('tapdata', '1/47CB8450')

这个计划的劣势是应用便捷, 创立复制槽后, 能够方便使用 SQL 查问增量数据
计划的问题有很多, 咱们遇到的列举在上面:

  1. 虚构 CDC 表不蕴含任何索引, 应用 where 条件查问性能很蹩脚
  2. 应用 pg_logical_slot_get_changes 会革除曾经读取的数据, 无奈实现多任务的数据复用, 只能创立多个互不关联的 slot 反对上游应用
  3. slot 数量受数据库配置限度, 无奈动静调整
  4. 忘记的 slot 会继续收缩, 占用数据库存储资源
  5. slot 不反对过滤, 忙碌的数据库上数据量微小, 即便在上游进行逻辑过滤, 其占用的带宽也难以避免
  6. 只能够在 主节点 应用, 在产生主从切换时, 机制会生效
  7. 不反对 DDL(构造变更, 比方表字段减少) 事件捕捉, 只反对 DML(数据增删改) 事件捕捉
  8. 不反对无惟一标记的 DML 事件捕捉, 惟一标记能够是主键, 也能够是惟一索引
  9. 须要源库日志开启到 logic 级别, 增大了存储占用
  10. 不反对回溯获取历史数据变更, 只能获取到开启 slot 之后的变更

即使问题如此之多, 然而因为其应用的便捷性, 对其进行二次开发的老本很低, 仍然成为各大数据集成组件里的首选计划, 这其中包含 debezium, flink-cdc, datax, flinkx 等等
手动治理日志解析

为了解决这些问题, 咱们须要能间接解析 WAL 的插件计划
Oracle 数据库有一个叫做 Logminer 的插件, 能够不便对数据库 Redo Log 进行逻辑解析, 对 PostgreSQL 也有一个相似的插件叫 Walminer, 我的项目地址在: movead/WalMiner

在应用上, 与手动治理的 Oracle Logminer 基本一致, 其具体的应用命令如下:

## 列出 WAL 文件
select walminer_wal_list()

## 增加 WAL 文件或者 WAL 文件目录到待解析
select walminer_wal_add('/opt/test/wal')

## 解析日志
select walminer_all()

## 解析指定工夫的 WAL 日志
select walminer_by_time(starttime, endtime)

## 解析指定 lsn 范畴的 WAL 日志
select walminer_by_lsn(startlsn, endlsn)

## 查看解析后果
select * from walminer_contents

## 销毁解析工作
select walminer_stop()

与基于复制槽的解码计划相比, Walminer 有本人的一些劣势, 包含:

  1. 能够解析任意时间段的日志, 不须要提前开启工作
  2. 不须要将日志级别设置为 logic, 节俭空间
  3. 反对 DML/DDL 事件解析
  4. 能够对后果表创立索引, 进行基于工夫和断点的范畴查问

他的劣势有:

  1. 后果表占用了数据库存储资源
  2. 日志解析占用了数据库计算资源
  3. 事件查问占用了数据库计算与带宽资源
  4. 不反对并发解析, 用户须要本人进行细粒度数据管理

相比复制槽解码插件, Walminer 从根本上解决了很多问题, 并疏导咱们思考这个计划的通用扩展性
原生裸日志解析
pgwal_dump 是 PostgreSQL 官网提供的 WAL 解析工具, 与 Walminer 相比, 其劣势在于不须要装置到数据库中, 且解析不占用数据库资源, 解析后的内容能够输入到文件中供上游生产, 官网提供, 有较好的维护性, 其劣势在于无奈应用数据库驱动进行工作治理, 须要额定装置通信 agent 进行工作治理, 且其输入后果无奈间接 SQL 查问, 须要自行组织后果数据

除此之外, 其外围性能与 Walminer 基本相同, 可作为备用计划应用
WAL 日志计划的反思
对数据库的设计者来说, 提供数据库事件的回放能力往往基于两个目标:

  1. 故障复原
  2. 主从同步

故障复原的场景应用低频, 数据实时性要求低, 多手动操作, 对集成性要求不高, pgwal_dump 是一个典型的例子, 对这个工具的集成应用须要额定开发 agent 进行工作治理, 减少了应用老本

主从同步有一个典型的特点是从的数量往往不是很多, 因而所有基于此假如的计划在遇到较多的生产上游时, 会遇到比较严重的性能问题, slot 的计划即是如此, 除此之外, 主从同步往往须要全量数据保持一致, 因而往往不会针对库, 表, 甚至更粗疏的查问条件进行特异性解析优化, 在应用时往往带来较大的资源节约

实时数据服务平台的需要突破了上述两个目标假如, 其场景既须要十分高的实时性, 又须要十分好的集成性, 同时对数据的生产数量与业务相干, 忙碌的数据库其生产场景会达到数十, 甚至数百个, 这些数据生产工作对数据的要求各不相同, 具备精密的过滤条件

在实时工作的开发过程中, 将工夫回退到某个工夫点进行回放是十分常见的调试需要, 已有的计划要么无奈实现, 要么以占用较多的数据库资源进行折衷, 在技术上不优雅

针对各种数据库, 以上的艰难都不止一次呈现在咱们背后, 客户在进行工作开发时, 须要小心翼翼设计工作过程, 防止对生产库造成影响, 对用户造成了较大的心智累赘

痛定思痛, 作为专一在实时数据开发的产品型公司, 这个问题被客户重复提起, 摆在研发团队背后, 通过屡次思考与尝试, 咱们应用了自研缓存中间件, 提出了本人的解决方案
TAP-CDC-CACHE
在软件开发畛域有一个名言, “All problems in computer science can be solved by another level of indirection”, 这个场景也不例外

为了解决这个问题, TAPDATA 对于各种起源的数据增量事件的写入和生产需要, 针对性开发了一个高速大容量的缓存层, 其具备以下根本个性:

  1. 分布式高可用: 基于 RAFT 的多正本同步机制, 可避免单点故障
  2. 无内部服务依赖: 部署便捷, 治理不便
  3. 丰盛的存储端数据过滤: 反对多字段, 多级字段, 字段等于, 字段范畴, IN Array, 多条件逻辑运算等过滤条件, 运行在服务端, 极大节俭带宽和生产端算力
  4. 反对多生产者 / 消费者, 反对主动推动, ACK 推动等生产形式
  5. 高性能: 极致数据吞吐能力, 单节点可满足每秒数百万的事件读写能力
  6. 大容量: 基于一般磁盘读写能力进行设计, 反对数据压缩, 满足常见业务场景极长时间的历史增量事件存储需要
  7. 严格程序保障: 针对同一个数据源的数据, 不应用分区存储, 保证数据的严格有序性, 尽管升高了局部解决性能, 然而对流计算场景来讲, 数据的准确性比性能更为重要

并针对 CDC 场景进行额定优化, 包含:

  1. 增量事件主动解析: 反对常见数据库事务日志格局, 原生写入, 主动解析并规整输入
  2. 事件补全: 基于全量数据 1:1 拷贝, 反对将局部不残缺的增量事件, 比方没有开启 Full 的 Oracle Redo Log, MongoDB Oplog 短少前值与残缺后值的状况, 对数据进行主动补全, 不便上游进行各种计算解决
  3. 事件共享: 对一个确定的数据源实例, 只须要对源库进行一份增量事件读取, 上游所有消费者从缓存层获取数据, 防止对源库造成较大压力
  4. 反对工夫和断点地位的双向转换: 通过大范畴二级索引查找与准确查找遍历相结合的形式, 转换速度快, 资源耗费少
  5. 对立数据规范检测: 对 DML/DDL 形容形象出一套异构数据库通用的形容, 包含对立可扩大的数据类型, 事件规范形容等规定, 并反对在缓存层进行检测, 保障进入上游的数据合乎品质要求
  6. 反对指定范畴的 全量 + 增量 主动合并后果返回, 在批流一体的准确一次数据输入场景, 能够做到对源库的无锁并发数据读取, 并极大简化了连接器的开发过程

这个中间件工作在数据采集层与计算层的两头地位, 屏蔽了数据库增量规范的差异性, 解决了之前计划遇到的各种问题, 为后续对数据的应用提供了足够的性能与性能空间, 为产品提供了独有的竞争力

几个常见的工作模式流程图如下:

典型工作模式

以 Oracle 为例, 开发者只须要将单并发实例级别无过滤的 Logminer Redolog 解析后果发送到缓存层, 后续的标准化, 有序性保障, 过滤器均可主动实现, 如下图所示

非标准日志补齐

以 MongoDB 为例, MongoDB 的 Update 须要开启反查能力获取残缺前值, Delete 操作不反对变更前值获取, 在流计算场景, 只有一个变更主键是不满足后续数据需要的, 比方对双流 JOIN 场景, JOIN 键不为主键时, 一条记录的删除除了须要通晓主键之外, 他的关联键和具体变更的数据也十分重要

针对这个场景, TAP-CDC-CACHE 的工作模式如下:

后言
提到数据流存储, 会有一些同学有为什么不应用 kafka, pulsar, 或者 pravega 这种产品的疑难, 处于解决问题老本最低的思考, 一开始的确有思考应用流存储, 与 Stream API 去开发一些解决算子来实现需求, 然而流存储这些开发接口, 实质上是对流做逐条变换, 一些外围的需要, 比方:

  1. 对不残缺事件进行补全
  2. 合并增量全量数据
  3. 工夫 / 断点互相转换等问题

这几个问题的技术形象应用逐条读取流曾经很勉强, 实现进去的成果并不好, 咱们不得不对一些特定的流做一些二级索引的保护, 这自身又须要独自一个组件来做, 这引入了一些额定的复杂性, 再思考到:

  1. 过滤器是十分耗费带宽的操作, 而常见的流存储产品不反对在 broker 进行计算
  2. 针对场景需要, 咱们须要开发较多的 Stream 中间件

咱们意识到本人的需要能够被更优雅和业余地解决, 于是有了这个产品的雏形,实质上来讲, TAP-CDC-CACHE 是一个特定场景下优化的数据库。
对于 Tapdata:
Tapdata 是一款基于数据即服务(DaaS)架构理念,面向 OLTP 业务或场景的实时数据服务平台,具备异构数据实时同步、批流一体数据交融、自助式 API 公布等性能。Tapdata 目前已反对近百个数据源和类型,包含市场支流的数据库,API,队列,物联网等,所有操作均是低代码、可视化形式,无需业余的编程能力就可实现数据实时同步、数据映射与合并、数据建模、数据服务 API 开发,数据实时入湖入仓等。申请试用:https://tapdata.net/tapdata-e…

本文作者:Tapdata 技术合伙人肖贝贝,原文地址:https://tapdata.net/TAP-CDC-C…

正文完
 0