什么是CDC
CDC(Change Data Capture)是变更数据捕获的简称。是一种用于监测和捕获数据库中数据变化的技术。CDC可以监听数据库中所做的变更(DDL和DMS(INSERT,UPDATE,DELETE))操作,并捕获这些变更的数据,按照发生的顺序完整的写入到消息中间件中以供其他服务进行订阅及消费。
简单来讲:CDC是指从源数据库捕获到数据和数据结构的增量变更,并将这些变更数据传递给其他系统或应用程序进行实时处理。 通过这种方式,CDC能够向数据仓库提供高效、低延迟的数据传输,以便信息被及时转换并交付给专供分析的应用程序。
CDC能做什么
数据分发 --将一个数据源的数据分发给多个业务系统,常用于业务解耦、微服务系统。
数据采集 --面向数据仓库、数据湖的ETL数据集成,消除数据孤岛,便于后续的分析。
数据同步 --常用于数据备份,容灾,ES索引,分布式缓存等。
数据审计 --谁谁谁在什么时间操作了什么数据,对数据审计和合规性要求非常重要,可以帮助企业满足监管和合规性标准
相比传统优势
业务解耦 --复杂的业务简单处理,保证核心业务稳定,减少强依赖,实现最终一致性
时效性高 --基于binlog的数据同步,能够保证数据的实时性,在毫秒时间内完成数据同步
提高效率 --无需依赖服务方提供接口,只需简单规则配置,订阅数据后快速开发上线
技术选型
基于binlog实现数据同步方案调研了两种:
一种是mysql-binlog-connector-java,另一种是阿里 Canal。
mysql-binlog-connector-java:是通过引入依赖jar包实现,需要自行解析binlog,但是相对轻量,开发成本较高。
canal:是数据同步中间件,需要单独部署,功能强大,较为稳定,需要运维帮助维护。
我们的目标是要做一个通用的CDC平台,需要考虑稳定性以及健壮性
Canal数据结构
CDC数据结构
规则引擎
规则引擎由推理引擎发展而来,是一种嵌入在应用程序中的组件,实现了将业务决策从应用程序代码中分离出来,并使用预定义的语义模块编写业务决策。接受数据输入,解释业务规则,并根据业务规则做出业务决策。
使用规则引擎的优势
- 业务规则与系统代码分离,实现业务规则的集中管理
- 在不重启服务的情况下可随时对业务规则进行扩展和维护
- 可以动态修改业务规则,从而快速响应需求变更
- 规则引擎是相对独立的,只关心业务规则,使得业务分析人员也可以参与编辑、维护系统的业务规则
- 减少了硬编码业务规则的成本和风险
- 使用规则引擎提供的规则编辑工具,使复杂的业务规则实现变得的简单
Maven依赖
Easy Rules是一个Java库, 需要运行在Java 1.7及以上。
xml
<!-- easy rules核心库 -->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-core</artifactId>
<version>4.1.0</version>
</dependency>
<!-- 支持mvel规则语法库 -->
<dependency>
<groupId>org.jeasy</groupId>
<artifactId>easy-rules-mvel</artifactId>
<version>4.1.0</version>
</dependency>
Easy Rules
Easy Rules -- 声明式方式
java
@Rule(name = "myRule1", description = "来源", priority = 1)
public class MyRule1 {
@Condition
public boolean when(@Fact("data") Map<String, Integer> data) {
return data.get("source") == 1;
}
@Action
public void then(@Fact("data") Map<String, Integer> data) {
data.put("source", data.get("source") + 1);
}
}
@Rule(name = "myRule2", description = "年龄", priority = 2)
public class MyRule2 {
@Condition
public boolean when(@Fact("data") Map<String, Integer> data) {
return data.get("age") == 1;
}
@Action
public void then(@Fact("data") Map<String, Integer> data) {
data.put("age", data.get("age") + 0);
}
}
Easy Rules -- 编程式方式
java
// 规则1
Rule rule1 = new RuleBuilder().priority(1).name("rule1").description("来源")
.when(f -> Integer.parseInt(((Map) f.get("data")).get("source").toString()) == 1)
.then(f -> ((Map) f.get("data")).put("source", Integer.parseInt(((Map) f.get("data")).get("source").toString()) + 1))
.build();
// 规则2
Rule rule2 = new RuleBuilder().priority(2).name("rule2").description("年龄")
.when(f -> Integer.parseInt(((Map) f.get("data")).get("age").toString()) == 18)
.then(f -> ((Map) f.get("data")).put("age", Integer.parseInt(((Map) f.get("data")).get("age").toString()) + 0))
.build();
Easy Rules -- 规则描述文件
java
---
priority: 1
name: "myRule1"
description: "来源"
condition: "data.get(\"source\") == 1"
actions:
- "data.put(\"source\", data.get(\"source\") + 1)"
---
priority: 2
name: "myRule2"
description: "年龄"
condition: "data.get(\"age\") == 18"
actions:
- "data.put(\"age\", data.get(\"age\") + 0)"
Easy Rules -- Mvel表达式
java
// 规则1
Rule rule1 = new MVELRule().priority(1).name("rule1").description("来源")
.when("data.source == 1")
.then("data.source = data.source + 1");
// 规则2
Rule rule2 = new MVELRule().priority(2).name("rule2").description("年龄")
.when("data.age == 18")
.then("data.age = data.age + 0");
Mvel表达式
MVEL为 MVFLEX Expression Language(MVFLEX表达式语言)的缩写,是一种基于Java语法,但又有着显著不同的表达式语言。与Java不同的是,MVEL是一种动态/静态可嵌入的表达式语言,意味着源代码中不需要类型限定。
简单说是一种表达式解析器。我们可以自己写一些表达式,交给mvel进行解析计算,得到这个表达式计算的值。
管理界面
数据库管理
数据库表管理
订阅主题管理
订阅规则管理
实战
系统容器加载完成后读取全部订阅主题信息,订阅规则信息
动态创建KAFKA消费者 (支持实时启停)
消费KAFKA消息 (canal 数据结构)
使用规则引擎处理数据
处理后的数据发送给订阅方