基于触发器实现 Sap Hana 实时数据同步

简介

SAP HANA(全称 SAP High-performance ANalytic Appliance)是由SAP开发的一款内置列式数据库的系统平台,除内置数据库以外,还具有高级分析功能(例如预测分析、空间数据处理、文本分析、文本搜索、流分析、图形数据处理),ETL功能,并内置了应用程序服务器,本文提到的 SAP HANA 特指数据平台内置的数据库管理系统。

SAP HANA 是内存数据库系统,可以把系统所有的数据都载入内存中,因此,与传统的将数据存储在硬盘上的数据库相比,HANA的性能可以提升10~10,000倍。一般SAP HANA 内置在 SAP ERP 系统中作为整体提供服务,在制造业应用广泛。

现如今企业都会建立内部的统一数据分析平台,SAP HANA 保存了ERP相关数据,如何实时同步 SAP HANA 的数据到数据平台,一直是困扰企业用户的问题。

CloudCanal 作为一款数据同步工具,新版本中支持 SAP HANA 同步到 MySQL、MariaDB、Doris、StarRocks。下面将介绍 CloudCanal 实现 SAP HANA 实时同步的原理。

整体流程

实现触发器同步的整体流程如下:

  1. 安装触发器,通过触发器捕获增量变更数据
  2. 记录位点,记录增量数据数据同步的起点
  3. 执行全量数据同步
  4. 执行增量数据同步

触发器安装

触发器是一种自动触发执行的存储过程,它可以在数据变更前执行也可以在数据变更后执行,因为本质也是存储过程,所以存储过程支持的操作触发器均支持。

不同数据库对触发器的支持程度不同,Hana 的触发器支持监听 I(新增)、U(更新)、(删除) 三种事件,因此数据的所有变更都可以通过触发器捕获。

安装触发器的方式与创建存储过程类似,即通过执行 SQL 创建触发器。

通过触发器实现增量数据同步,需要触发器捕获数据的变更事件并写入 增量CDC数据表, 下面是触发器执行的整体流程:

触发器安装示例

下面是安装触发器的示例脚本

sql 复制代码
CREATE OR REPLACE TRIGGER "MY_SCHEMA"."SYM_ON_I_FOR_TST1_CRP" AFTER INSERT ON "MY_SCHEMA"."TEST1" 
REFERENCING NEW ROW NEW FOR EACH ROW 
BEGIN 
  DECLARE NEW_KEY_SUMMARY CLOB := '"COL1":' || CASE WHEN :NEW."COL1" IS NULL THEN 'null' ELSE CONCAT(CONCAT('"',REPLACE(REPLACE(:NEW."COL1",'\','\\'),'"','\"')),'"') END; 
  DECLARE NEW_COL_SUMMARY CLOB := '"COL1":' || CASE WHEN :NEW."COL1" IS NULL THEN 'null' ELSE CONCAT(CONCAT('"',REPLACE(REPLACE(:NEW."COL1",'\','\\'),'"','\"')),'"') END || ',' || '"COL0":' || CASE WHEN :NEW."COL0" IS NULL THEN 'null' ELSE CONCAT(CONCAT('"',REPLACE(REPLACE(:NEW."COL0",'\','\\'),'"','\"')),'"') END; 
  DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN END; 
 
  IF 1=1 THEN 
    INSERT INTO "SYSTEM"."CLOUD_CANAL_TRIGGER_DATA" (CATALOG_NAME, SCHEMA_NAME, TABLE_NAME, EVENT_TYPE, TRIGGER_ID, PK_DATA, ROW_DATA, TRANSACTION_ID, EXTERNAL_DATA, CREATE_TIME) 
    VALUES( 
      'SYSTEMDB', 
      'MY_SCHEMA', 
      'TEST1', 
      'I', 
      1, 
      '{' || NEW_KEY_SUMMARY || '}', 
      '{' || NEW_COL_SUMMARY || '}', 
      CURRENT_UPDATE_TRANSACTION(), 
      '', 
      CURRENT_UTCTIMESTAMP 
    ); 
  END IF; 
 
END;

安装好触发器,下面介绍 增量CDC数据表 的具体结构设计

CDC 增量表

增量CDC数据表结构如下:

sql 复制代码
CREATE COLUMN TABLE "SYSTEM"."CLOUD_CANAL_TRIGGER_DATA" ("DATA_ID" BIGINT GENERATED BY DEFAULT AS IDENTITY (
START WITH 1 INCREMENT BY 1) NOT NULL ,
    "CATALOG_NAME" VARCHAR(255) NULL ,
    "SCHEMA_NAME" VARCHAR(255) NOT NULL ,
    "TABLE_NAME" VARCHAR(255) NOT NULL ,
    "EVENT_TYPE" VARCHAR(20) NOT NULL ,
    "ROW_DATA" CLOB,
    "PK_DATA" CLOB,
    "OLD_DATA" CLOB,
    "TRIGGER_ID" INTEGER NOT NULL ,
    "EXTERNAL_DATA" VARCHAR(50),
    "CREATE_TIME" LONGDATE
);
CREATE UNIQUE CPBTREE INDEX "CLOUD_CANAL_IDX_D_ID" ON
"SYSTEM"."CLOUD_CANAL_TRIGGER_DATA" ( "DATA_ID" ASC);
CREATE INDEX CLOUD_CANAL_TRIGGER_DATA_CREATE_TIME_IDX ON "SYSTEM".CLOUD_CANAL_TRIGGER_DATA (CREATE_TIME);

增量CDC数据表记录了每次变更数据的

  • 数据库(CATALOG_NAME)
  • 模式名称(SCHEMA_NAME)
  • 表名称(TABLE_NAME)
  • 事件类型(EVENT_TYPE)
  • 变更前的数据镜像(ROW_DATA)
  • 变更前主键数据(PK_DATA)
  • 变更后的数据镜像(OLD_DATA)
  • 触发器ID(TRIGGER_ID)
  • 变更时间(CREATE_TIME)

另外,需要注意的是使用 自增ID 作为主键,同时记录 创建时间

自增ID(DATA_ID)可以唯一标识数据变更事件并确保有序,创建时间(CREATE_TIME)作为数据变更事件的时间戳,记录数据变更发生时间。

增量表定时清理

触发器将增量数据写入增量表后,若未及时清理,可能导致空间占用增加。

在 CloudCanal 中可以设置任务参数 triggerDataCleanEnabled 打开自动定时清理增量表功能,并提供两个参数进行控制:

  • triggerDataCleanIntervalMin:增量表清理间隔(单位:分钟)
  • triggerDataRetentionMin:增量表数据保留时间(单位:分钟)

通过这套机制,用户能够灵活控制增量表的清理操作,同时确保未消费的增量数据不会被意外清除。

增量表自动演进

Hana 增量任务创建时自动生成增量表,CloudCanal 依赖于增量表实现各种能力,但随着 CloudCanal 版本更新,可能对增量表进行变更(比如加入新字段)。

由此带来的问题是:用户在更新 CloudCanal 后需要手动执行 DDL 以适应增量表结构的变化,若存在大量增量表,操作相当复杂。

为解决此问题,CloudCanal 新增 增量表结构 DIFF 能力 ,在任务启动时 自动生成差异 DDL 实现对增量表的自动演进

扫描 CDC 增量表

扫描 CDC 增量表 需要做到不重复扫、不漏数据、顺序扫描。

保证顺序的方式是通过自增ID排序,即 ORDER BY DATA_ID ASC,通过这个方式相当于对全局的变更事件进行编号,基于编号进行扫描和消费,可确保不重。但只做到这一点还不够,会出现丢数据情况,数据丢失的原因如图所示:

当查询的语句执行时,可能有部分事务没有 COMMIT,导致漏扫,这种问题如何解决?

首先想到的可能是等待一段时间,但是等待多久合适也是问题,时间长了延迟高,时间短了丢数据,而且当事务出现回滚时,自增序列会出现缺失,缺失的原因是事务没有回滚前占用了自增 ID 生成的序号,事务回滚后占用的序号也不会被重复使用。遇到自增 ID 序号缺失的情况,通过等待一段时间方式,只能每次都等待最大超时时间,会导致同步延迟增大。

这个问题的关键点是确定占用自增ID的事务是否还在活跃状态。

CloudCanal 采用的解决办法是 查缺补漏 ,在扫描 增量CDC数据表 时遇到某个数据 ID 缺失的情况,会尝试插入一条相同 ID 的数据,通过唯一键来判断这个 ID 的数据是否被占用,如果出现异常,则重新查询;如没有异常,则会写入数据占用这个 ID,因为这个 ID 的数据已经被填充,因此也不用担心这个 ID 的数据被漏扫,可以继续读取大于这个 ID 数据。

位点管理

位点用于管理数据同步的进度,记录哪些变更事件已经同步、哪些变更事件没有同步。

基于触发器的数据同步方案选择 CDC 增量表的自增 ID 及时间戳作为位点,自增 ID 可以精确定位到每个数据变更事件,时间戳可以方便以用户视角感知同步任务的延迟情况。

什么时候更新位点?

当捕获的变更事件成功写入目标端后更新位点,如果写入数据成功更新位点失败会导致数据不一致吗?

答案是 不会,因为源端的变更事件是顺序保存并且顺序读取,类似 Mysql Binlog,只要 CloudCanal 按照源端的事件顺序消费,当消费到事件末尾时可以确保源端和目标端的的数据状态一致。

如何判断同步延迟?

Hana 源端增量同步使用位点(增量表自增ID)来判断延迟,当位点向前推进时可准确获取延迟,但若无变更事件导致位点不更新,延迟会持续增大,实际上并未发生延迟。

为解决这一问题,CloudCanal 通过查询增量表来判断是否存在延迟,具体逻辑为:

  • 若存在数据,系统根据增量数据的时间戳计算延迟。
  • 若无数据,任务获取当前时间发送心跳事件,并根据心跳上的时间戳计算延迟。

时间戳仅在重置位点时才用于数据查找,且在查找时进行时区转换处理。

同步演示

添加数据源

  • 数据源管理 -> **添加数据源, 添加 Sap Hana、MySQL

创建同步任务

  • 任务管理 -> 新建任务

  • 选择需要迁移同步的列 ,目标映射规则可选择与源端一致转小写

  • 任务自动做结构迁移全量迁移增量同步

测试同步

  • 利用造数据工具对 Hana 进行随机增删改操作。
  • 数据同步结束后校验 Hana 和 MySQL 的数据,40 万左右的数据是一致的。

总结

本文简要介绍 CloudCanal 数据迁移工具近期对 Hana 源端数据同步的设计思路,希望对读者有所帮助。

相关推荐
小码的头发丝、25 分钟前
Django中ListView 和 DetailView类的区别
数据库·python·django
Karoku06635 分钟前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix
周全全1 小时前
MySQL报错解决:The user specified as a definer (‘root‘@‘%‘) does not exist
android·数据库·mysql
白云如幻1 小时前
MySQL的分组函数
数据库·mysql
荒川之神2 小时前
ORACLE 闪回技术简介
数据库·oracle
时差9533 小时前
【面试题】Hive 查询:如何查找用户连续三天登录的记录
大数据·数据库·hive·sql·面试·database
让学习成为一种生活方式3 小时前
R包下载太慢安装中止的解决策略-R语言003
java·数据库·r语言
秋意钟3 小时前
MySQL日期类型选择建议
数据库·mysql
Dxy12393102164 小时前
python下载pdf
数据库·python·pdf
桀桀桀桀桀桀5 小时前
数据库中的用户管理和权限管理
数据库·mysql