Debezium官方地址:
https://docs.redhat.com/zh-cn/documentation/red_hat_build_of_debezium/2.3.7/html/debezium_user_guide/index
Debezium 是一组分布式服务,用于捕获数据库中的行级更改,以便您的应用程序能够查看和响应这些更改。Debezium 记录提交到每个数据库表的所有行级更改。每个应用程序都会读取感兴趣的事务日志,以按照发生的顺序查看所有操作。
Debezium就是监听数据库的binlog(前提是mysql要打开binlog,其他数据库也一样),从而实现感知数据变化,然后通知我们的应用。
Debezium可以监听常见的数据库,有Mysql、Postgres、Mongodb、Oracle、SqlServer、Db2等,debezium其中对应的概念叫连接器,不同的数据库用不同的连接器实现监听。
架构描述
如图中所示,部署了 MySQL 和 PostgresSQL 的 Debezium 连接器,以捕获对这两种类型的数据库的更改。每个 Debezium 连接器建立与源数据库的连接:
-
MySQL 连接器使用客户端库来访问 binlog。
-
PostgreSQL 连接器从逻辑复制流读取。
-
Kafka Connect 作为 Kafka 代理之外的独立服务运行。
默认情况下,从一个数据库表的更改写入 Kafka 主题,其名称对应于表名称。如果需要,可以通过配置 Debezium 的主题 路由转换来调整目标主题名称。例如,:
将记录路由到名称与表名称不同的主题
流将多个表的事件记录改为单个主题
在 Apache Kafka 中更改了事件记录后,Kafka Connect eco-system 的不同连接器可以将记录流传输到其他系统和数据库,如 Elasticsearch、数据仓库和分析系统或缓存,如 Infinispan。根据所选的 sink 连接器,您可能需要配置 Debezium 的新记录状态提取转换。此 Kafka Connect SMT 将 after 结构从 Debezium 的更改事件传播到接收器连接器。
mysql连接器应用
以SpringBoot项目为例,整合debezium实现数据库的监听,然后再处理下游的数据动作。
一、导入maven依赖:
<debezium.version>1.5.2.Final</debezium.version>
<dependency> <groupId>io.debezium</groupId> <artifactId>debezium-api</artifactId> <version>${debezium.version}</version></dependency>
<dependency> <groupId>io.debezium</groupId> <artifactId>debezium-embedded</artifactId> <version>${debezium.version}</version></dependency>
<dependency> <groupId>io.debezium</groupId> <artifactId>debezium-connector-mysql</artifactId> <version>${debezium.version}</version></dependency>
二、将数据库的信息配置到yml配置文件中
debezium: mysql: ## name可以自己起一个 name: mysql-connector ## 连接器类型 connector-class: io.debezium.connector.mysql.MySqlConnector database-hostname: 你的数据库地址 database-port: 端口 database-user: 用户 database-password: 密码 database-server-name: customer-mysql-db-server database-history: io.debezium.relational.history.FileDatabaseHistory database-history-filename: E:/google download/spring-boot-debezium-master/dbhistory.dat offset-storage: org.apache.kafka.connect.storage.FileOffsetBackingStore offset-storage-filename: E:/google download/spring-boot-debezium-master/offsets.dat offset-flush-interval-ms: 6000 ## 要监听哪些表,可以是多个,database.table的格式 table-include-list: db.sys_user,db.risk include-schema-changes: false database-server-id: 1
三,配置类读取配置的信息
@Configuration@ConfigurationProperties(prefix = "debezium.mysql")@Data@Slf4jpublic class MysqlDebeziumConfiguration { private String name; private String connectorClass; private String databaseHostname; private String databasePort; private String databaseUser; private String databasePassword; private String databaseServerName; private String databaseHistory; private String databaseHistoryFilename; private String offsetStorage; private String offsetStorageFilename; private int offsetFlushIntervalMs; private String tableIncludeList; private String includeSchemaChanges; private String databaseServerId; public Properties buidProperties() { Properties pros = new Properties(); pros.put("name", getName()); pros.put("connector.class", getConnectorClass()); pros.put("database.hostname", getDatabaseHostname()); pros.put("database.history", getDatabaseHistory()); pros.put("database.port", getDatabasePort()); pros.put("database.user", getDatabaseUser()); pros.put("database.password", getDatabasePassword());// pros.put("database.server.id", getDatabaseServerId()); pros.put("database.history.file.filename", getDatabaseHistoryFilename()); pros.put("database.server.name", getDatabaseServerName()); pros.put("offset.storage", getOffsetStorage()); pros.put("offset.storage.file.filename", getOffsetStorageFilename()); pros.put("offset.flush.interval.ms", getOffsetFlushIntervalMs()); // mysql中是[database.tableName],多个表以,分割 pros.put("table.include.list", getTableIncludeList()); pros.put("include.schema.changes", getIncludeSchemaChanges()); return pros; }
private static void checkFileExists(String absolutePath) { String dir = absolutePath.substring(0, absolutePath.lastIndexOf("/")); String fileName = absolutePath.substring(absolutePath.lastIndexOf("/") + 1); System.out.println("file name" + fileName); System.out.println("dir " + dir); File dirFile = new File(dir); if (!dirFile.exists()) { dirFile.mkdirs(); } File file = new File(absolutePath); if (!file.exists()) { try { boolean res = file.createNewFile(); log.info("{} 文件不存在,新建文件:{}", absolutePath, res); } catch (IOException e) { log.info("{} 文件新建失败, msg: {}", absolutePath, e.getMessage()); throw new RuntimeException(e); } } }}
四,编写一个类,用来启动debezium引擎
@Datapublic class DebeziumServerBootstrap implements InitializingBean, SmartLifecycle { private final Executor executor = Executors.newSingleThreadExecutor(); private DebeziumEngine<?> debeziumEngine; @Override public void start() { executor.execute(debeziumEngine); } @SneakyThrows @Override public void stop() { debeziumEngine.close(); }
@Override public boolean isRunning() { return false; }
@Override public void afterPropertiesSet() throws Exception { Assert.notNull(debeziumEngine, "debeziumEngine must not be null"); }
}
五,将其注册为一个bean,让spring容器维护运行。
@Configurationpublic class DebeziumConfiguration { @Autowired private MysqlDebeziumConfiguration debeziumConfiguration;
@Bean DebeziumServerBootstrap debeziumServerBootstrap() { DebeziumServerBootstrap debeziumServerBootstrap = new DebeziumServerBootstrap(); DebeziumEngine<RecordChangeEvent<SourceRecord>> debeziumEngine = DebeziumEngine.create(ChangeEventFormat.of(Connect.class)) .using(debeziumConfiguration.buidProperties()) .notifying(DebeziumHandler::notifyEvent) .build(); debeziumServerBootstrap.setDebeziumEngine(debeziumEngine); return debeziumServerBootstrap; }}
六,最后封装一下发送的动作事件
public class DebeziumHandler { public static void notifyEvent(List<RecordChangeEvent<SourceRecord>> recordChangeEvents, DebeziumEngine.RecordCommitter<RecordChangeEvent<SourceRecord>> recordCommitter) { recordChangeEvents.forEach(r -> { System.out.println("========================change = " + r); SourceRecord sourceRecord = r.record(); System.out.println("========================sourceRecord = " + sourceRecord); Struct sourceRecordChangeValue = (Struct) sourceRecord.value(); if (sourceRecordChangeValue != null) { // 判断操作的类型 过滤掉读 只处理增删改 这个其实可以在配置中设置 Envelope.Operation operation = Envelope.Operation.forCode((String) sourceRecordChangeValue.get(OPERATION)); if (operation != Envelope.Operation.READ) { String record = operation == Envelope.Operation.DELETE ? BEFORE : AFTER; // 获取增删改对应的结构体数据 Struct struct = (Struct) sourceRecordChangeValue.get(record); // 将变更的行封装为Map Map<String, Object> payload = struct.schema().fields().stream() .map(Field::name) .filter(fieldName -> struct.get(fieldName) != null) .map(fieldName -> Pair.of(fieldName, struct.get(fieldName))) .collect(toMap(Pair::getKey, Pair::getValue)); // 这里简单打印一下 System.out.println(operation+ ":payload = " + payload); } } }); }}
最后启动项目运行一下,手动去更改一下数据库中的数据,就可以看到此时已经监听到变化了,就会有相应的日志打印。
如果删除或者更新数据库中的数据,就会通知我们的应用程序,打印相应的日志
总结
Debezium对于监听常见数据库的数据变化是非常适合的,也可以方便的集成进我们自己的项目,帮我们处理了复杂的过程,我们只需要简单的做好下游数据处理即可。
原文:如何实现实时监听mysql数据库变化Mysql数据库实现实时数据监听,实现动态实时数据处理https://mp.weixin.qq.com/s/wPRW4E0e_RpKvVLsTtm6VQ