CDC系列(三)、Debezium 监控MySQL操作日志实时同步到Kafka(对比canal,maxwell)

本文介绍如何使用 Debezium 监控 MySQL 操作日志,并实时同步到 Kafka 中。涵盖 Debezium 的安装配置、通过 Kafka Connect 启动 MySQL Connector 的步骤,以及如何验证 CDC 功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

前言

准备工作

配置Connector

注册启动Connector

验证CDC

尾巴


CDC系列:

CDC系列(一)、Canal 集群部署及使用(带WebUI)

CDC系列(二)、Maxwell_v1.27.1 监控MySQL操作日志实时同步到Kafka


前言

前两篇我们介绍了CDC工具,以及利用Canal和Maxwell监控mysql操作日志并写入kafka,本篇我们来讲解另一个CDC工具:debezium。debezium不仅仅支持mysql的监控,目前最新版已支持mysql,postgre,mongodb,oracle,sqlserver,db2,cassandra等,它依赖于kafka connect 服务,通过kafka connect,我们可以很方便的将debezium采集到的数据库日志输出到各类目标端。

本篇我们演示如何利用kafka connect启动debezium mysql connector监控mysql 数据库操作日志并写入kafka内

准备工作

上面提到debezium依赖于kafka connect ,而且kafka connect是在0.9版本之后才由confluent团队贡献出来,因此我们必须要先安装好kafka0.9+版本,如果没有的话也可以参考我之前的文章:

由于我们要监控mysql的binlog,因此还需要一个可以访问mysql binlog权限的用户,这个操作在前面两篇有介绍就不在此赘述了。

配置Connector

1. 下载,到官方网址下载最新1.2 版debezium-mysql-connector:Debezium Release Series 1.2

2. 配置kafka connect服务

1. 在kafka目录下新建一个文件夹
mkdir /opt/app/lib_conn

2. 将下载的debezium插件上传至服务器并解压至刚才创建的目录
tar -zxvf debezium-connector-mysql-1.2.5.Final-plugin.tar.gz -C /opt/app/lib_conn

3. 修改kafka connect 配置文件
vim /opt/app/kafka/connect-standalone.properties
#----------------------
#修改下面的几个参数,其他的不变
bootstrap.servers=wykd:9092
plugin.path=/opt/app/kafka_2.11-2.4.1/lib_conn  #指向刚才放置debezium插件的目录

#这两个参数表示connect消息格式,可选json或avro,在消费的时候也需要使用对应的格式,本次我们使用json格式
key.converter=org.apache.kafka.connect.json.JsonConverter
value.converter=org.apache.kafka.connect.json.JsonConverter

3. 配置debezium mysql connector

创建debezium mysql connector插件配置文件,核心参数如下,其他参数请参考官方手册:mysql-connector-configuration-properties_debezium

#修改kafka connect 配置文件
vim /opt/app/kafka/connect-debezium-mysql-wyk-csdn.properties
#----------------------
name=wyk_csdn_mysql_debezium_connector    #connector 名称,唯一
connector.class=io.debezium.connector.mysql.MySqlConnector  #connector 插件
database.hostname=wykd        #数据库host
database.port=3306            #数据库port
database.user=root            #数据库user 有复制binlog权限
database.password=123456      #数据库password
database.server.id=9999       # server id 同一个数据库的serverId不能有重复的
database.server.name=wyk_sandbox    # server name [记录DDL动作的topic名称,给消费端使用的]
database.whitelist=testschema       # schema白名单,只监控白名单库下的,和blacklist参数互相冲突
database.history.kafka.bootstrap.servers=wykd:9092  # kafka
database.history.kafka.topic=wyk_csdn_debezium_mysql  #记录所有schema变动记录的topic[给连接器使用的]
include.schema.changes=true  # 监控schema变动,写入一个名称和server name一样的topic内
include.query=true        # 将执行的sql也记录下来,需要mysql端的参数binlog_rows_query_log_events=ON

注意:

配置文件中每行参数前后不能有空格;

如果需要在消息内记录执行的sql,需要:

  • mysql:set global binlog_rows_query_log_events=ON;
  • debezium mysql connect配置文件:include.query=true

需要特别关注的几个参数:whitelist、blacklist、include.query、include.schema.changes、snapshot.mode

注册启动Connector

如果当前kafka没有启动kafka connect服务,则使用下面的命令启动并注册connect到kafka:

cd $KAFKA_HOME
bin/connect-standalone.sh config/connect-standalone.properties config/connect-debezium-mysql-wyk-csdn2.properties

启动成功后,会一并启动kafka rest服务,我们可以使用restful api的方式查看或管理connectors:

GET /Connectors:返回活跃的 Connector 列表
POST /Connectors:创建一个新的 Connector;请求的主体是一个包含字符串name字段和对象 config 字段(Connector 的配置参数)的 JSON 对象。
GET /Connectors/{name}:获取指定 Connector 的信息
GET /Connectors/{name}/config:获取指定 Connector 的配置参数
PUT /Connectors/{name}/config:更新指定 Connector 的配置参数
GET /Connectors/{name}/status:获取 Connector 的当前状态,包括它是否正在运行,失败,暂停等。
GET /Connectors/{name}/tasks:获取当前正在运行的 Connector 的任务列表。
GET /Connectors/{name}/tasks/{taskid}/status:获取任务的当前状态,包括是否是运行中的,失败的,暂停的等,
PUT /Connectors/{name}/pause:暂停连接器和它的任务,停止消息处理,直到 Connector 恢复。
PUT /Connectors/{name}/resume:恢复暂停的 Connector(如果 Connector 没有暂停,则什么都不做)
POST /Connectors/{name}/restart:重启 Connector(Connector 已故障)
POST /Connectors/{name}/tasks/{taskId}/restart:重启单个任务 (通常这个任务已失败)
DELETE /Connectors/{name}:删除 Connector, 停止所有的任务并删除其配置

在浏览器查看当前活跃的connectors: ip:8083/connectors

例:此时我们想再注册一个debezium mysql connector服务的话就不能用刚刚的命令启动了,会报错提示Failed to bind to 0.0.0.0/0.0.0.0:8083,Caused by: java.net.BindException: Address already in use。这里的8083端口就是kafka connect服务,因此我们只能使用下面的命令来注册新的connector:

# 这里的 connector 配置需要使用json格式
curl -s http://10.1.174.10:8083/connectors -X POST -H "Content-Type: application/json" --data \
'{"name": "wyk_csdn_mysql_debezium_connector2","config": {"connector.class": "io.debezium.connector.mysql.MySqlConnector", "database.hostname": "10.1.174.10", "database.port": "3306", "database.user": "root", "database.password": "123456", "database.server.id": "9988", "database.server.name": "wyk_sandbox", "database.whitelist": "canal_manager", "database.history.kafka.bootstrap.servers": "10.1.174.10:9092 ", "database.history.kafka.topic": "wyk_csdn_debezium_mysql2", "include.schema.changes": "true","include.query":"true" }}'

例:使用rest api管理kafka connectors:

# 查看所有活跃的connectors
curl -s http://10.1.174.10:8083/connectors -X GET

# 注册一个新的connector
curl -s http://10.1.174.10:8083/connectors -X POST -H "Content-Type: application/json" --data \
'{"name": "wyk_csdn_mysql_debezium_connector2","config": {"connector.class": "io.debezium.connector.mysql.MySqlConnector", "database.hostname": "10.1.174.10", "database.port": "3306", "database.user": "root", "database.password": "123456", "database.server.id": "9988", "database.server.name": "wyk_sandbox", "database.whitelist": "canal_manager", "database.history.kafka.bootstrap.servers": "10.1.174.10:9092 ", "database.history.kafka.topic": "wyk_csdn_debezium_mysql", "include.schema.changes": "true","include.query":"true" }}'

# 删除指定的connector
curl -s http://10.1.174.10:8083/connectors/wyk_csdn_mysql_debezium_connector2 -X DELETE

验证CDC

此时我们已经启动了debezium mysql connect来监控指定的mysql并将数据写入了kafka,和maxwell,canal不同的是,debezium监控的消息会将每张表对应一个topic,且该topic只包含该表的增删改(insert/delete/update)操作,DDL操作如create/drop/truncate/rename/alter等命令会统一写入以配置文件中的database.server.name 参数的值为名称的topic内。

Topic 命名方式:对于同一个connector 监控的数据范围,一张表对应一个topic,该范围内所有库所有表的DDL操作记录在同一个topic内:

  • DDL topic:serverName
  • DML topic:serverName.databaseName.tableName

默认情况下,为了提升性能及保证数据一致性,在第一次启动时并不会从binlog回放表的每个操作来同步数据,而是通过一个全局读锁将表的快照直接同步到对应的topic内,这个过程很快,在同步完成后才会继续监控binlog内的操作达到初始化时全量切实时的目的。该快照模式的参数在connector配置文件中为 snapshot.mode,有下面几个可选的值:

  • initial:默认值,第一次启动connector时同步数据快照,完成后再从记录的binlog位置开始同步,但当关闭connector很久以后再次启动时若上次记录的Offset在binlog内已经被删除的时候就会启动失败(建议mysql保留全部binlog);
  • when_needed:在有必要的任何时候执行快照任务,和initial类似,不同的是当遇到故障时如binlog丢失时会重新发起一个快照同步;
  • never:永不执行快照同步,从Binlog记录的位置回放;
  • schema_only:从第一次启动后记录当前schema,然后从binlog位置开始同步,仅同步schema变动而不同步数据;
  • schema_only_recovery:仅同步schema变更而不同步数据,只能配置于已有的connector之上,不是从当前启动时记录schema而是从已存在的connector上次记录的位置开始;

消息体: 分为两种,一个记录DDL,一个记录DML

DDL:schema_change_topic_structure

DML:change_event_values ,默认会使用primary key 或unique key作为消息体的key,也可自定义key。

DML中insert对应的op为c,update对应为u,delete对应为d。 

例:

DDL:

{
	"schema": {
		"type": "struct",
		"fields": [
			{
				"type": "struct",
				"fields": [
					{
						"type": "string",
						"optional": false,
						"field": "version"
					},
					{
						"type": "string",
						"optional": false,
						"field": "connector"
					},
					{
						"type": "string",
						"optional": false,
						"field": "name"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "ts_ms"
					},
					{
						"type": "string",
						"optional": true,
						"name": "io.debezium.data.Enum",
						"version": 1,
						"parameters": {
							"allowed": "true,last,false"
						},
						"default": "false",
						"field": "snapshot"
					},
					{
						"type": "string",
						"optional": false,
						"field": "db"
					},
					{
						"type": "string",
						"optional": true,
						"field": "table"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "server_id"
					},
					{
						"type": "string",
						"optional": true,
						"field": "gtid"
					},
					{
						"type": "string",
						"optional": false,
						"field": "file"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "pos"
					},
					{
						"type": "int32",
						"optional": false,
						"field": "row"
					},
					{
						"type": "int64",
						"optional": true,
						"field": "thread"
					},
					{
						"type": "string",
						"optional": true,
						"field": "query"
					}
				],
				"optional": false,
				"name": "io.debezium.connector.mysql.Source",
				"field": "source"
			},
			{
				"type": "string",
				"optional": false,
				"field": "databaseName"
			},
			{
				"type": "string",
				"optional": false,
				"field": "ddl"
			}
		],
		"optional": false,
		"name": "io.debezium.connector.mysql.SchemaChangeValue"
	},
	"payload": {
		"source": {
			"version": "1.2.2.Final",
			"connector": "mysql",
			"name": "wyk_sandbox",
			"ts_ms": 1601016725000,
			"snapshot": "false",
			"db": "testschema",
			"table": "wyk_csdn",
			"server_id": 1,
			"gtid": null,
			"file": "mysql-bin.000016",
			"pos": 93212,
			"row": 0,
			"thread": null,
			"query": null
		},
		"databaseName": "testschema",
		"ddl": "create table wyk_csdn(id int,name varchar(20),ins_ts timestamp)"
	}
}

DML:

{
	"schema": {
		"type": "struct",
		"fields": [
			{
				"type": "struct",
				"fields": [
					{
						"type": "int32",
						"optional": true,
						"field": "id"
					},
					{
						"type": "string",
						"optional": true,
						"field": "name"
					},
					{
						"type": "string",
						"optional": true,
						"name": "io.debezium.time.ZonedTimestamp",
						"version": 1,
						"field": "ins_ts"
					}
				],
				"optional": true,
				"name": "wyk_sandbox.testschema.wyk_csdn.Value",
				"field": "before"
			},
			{
				"type": "struct",
				"fields": [
					{
						"type": "int32",
						"optional": true,
						"field": "id"
					},
					{
						"type": "string",
						"optional": true,
						"field": "name"
					},
					{
						"type": "string",
						"optional": true,
						"name": "io.debezium.time.ZonedTimestamp",
						"version": 1,
						"field": "ins_ts"
					}
				],
				"optional": true,
				"name": "wyk_sandbox.testschema.wyk_csdn.Value",
				"field": "after"
			},
			{
				"type": "struct",
				"fields": [
					{
						"type": "string",
						"optional": false,
						"field": "version"
					},
					{
						"type": "string",
						"optional": false,
						"field": "connector"
					},
					{
						"type": "string",
						"optional": false,
						"field": "name"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "ts_ms"
					},
					{
						"type": "string",
						"optional": true,
						"name": "io.debezium.data.Enum",
						"version": 1,
						"parameters": {
							"allowed": "true,last,false"
						},
						"default": "false",
						"field": "snapshot"
					},
					{
						"type": "string",
						"optional": false,
						"field": "db"
					},
					{
						"type": "string",
						"optional": true,
						"field": "table"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "server_id"
					},
					{
						"type": "string",
						"optional": true,
						"field": "gtid"
					},
					{
						"type": "string",
						"optional": false,
						"field": "file"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "pos"
					},
					{
						"type": "int32",
						"optional": false,
						"field": "row"
					},
					{
						"type": "int64",
						"optional": true,
						"field": "thread"
					},
					{
						"type": "string",
						"optional": true,
						"field": "query"
					}
				],
				"optional": false,
				"name": "io.debezium.connector.mysql.Source",
				"field": "source"
			},
			{
				"type": "string",
				"optional": false,
				"field": "op"
			},
			{
				"type": "int64",
				"optional": true,
				"field": "ts_ms"
			},
			{
				"type": "struct",
				"fields": [
					{
						"type": "string",
						"optional": false,
						"field": "id"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "total_order"
					},
					{
						"type": "int64",
						"optional": false,
						"field": "data_collection_order"
					}
				],
				"optional": true,
				"field": "transaction"
			}
		],
		"optional": false,
		"name": "wyk_sandbox.testschema.wyk_csdn.Envelope"
	},
	"payload": {
		"before": null,
		"after": {
			"id": 2,
			"name": "wyk2",
			"ins_ts": "2020-09-25T08:10:22Z"
		},
		"source": {
			"version": "1.2.2.Final",
			"connector": "mysql",
			"name": "wyk_sandbox",
			"ts_ms": 1601021422000,
			"snapshot": "false",
			"db": "testschema",
			"table": "wyk_csdn",
			"server_id": 1,
			"gtid": null,
			"file": "mysql-bin.000016",
			"pos": 97798,
			"row": 0,
			"thread": 162,
			"query": "insert into wyk_csdn values(2,'wyk2',current_timestamp())"
		},
		"op": "c",
		"ts_ms": 1601021422679,
		"transaction": null
	}
}

另外如果使用confluent platform,可以在control center中直接查看管理connectors以及查看topic内的数据:

尾巴

优点: 

  1. debezium支持全DDL(create/alter/rename/drop/truncate)和DML(insert/update/delete)的操作日志同步;(Maxwell不支持truncate命令同步)
  2. 支持使用数据的主键或唯一键作为消息体的key(可以根据该唯一键做Topic分区进行负载均衡);
  3. 支持快照模式(snapshot.mode)全量同步;(Canal不支持全量,Maxwell支持bootstrap全量)
  4. 还支持多种数据源(MySQL,Oracle,Postgre,MongoDB,SqlServer,DB2,Cassandra),比Canal,Maxwell功能更强大;
  5. 社区活跃,与kafka connect配合使用如虎添翼。

缺点:

  1. 需要kafka connect依赖;
  2. 消息体内容太多,对消息队列压力较大;(可使用transforms 模块进行压缩和定制)
  3. 每张表对应一个topic,管理起来不够方便(canal,maxwell则可以使用正则来处理); (可使用transforms 模块进行压缩和定制)

希望本文对你有帮助,请点个赞鼓励一下作者吧~ 谢谢!

### 开源免费框架实时同步 Oracle ASM 日志 #### 背景分析 Oracle Automatic Storage Management (ASM) 是一种专为管理数据库文件设计的存储解决方案[^3]。然而,ASM 的日志本身并不直接暴露给外部工具进行解析和同步。为了实现实时同步 Oracle ASM 日志的功能,通常需要借助于能够捕获数据库变更并将其转换为可消费数据流的技术。 目前主流的开源框架和技术主要集中在以下几个方面: 1. **基于归档日志的解析**:如 Oracle Streams 或 LogMiner 技术[^2]。 2. **CDC(Change Data Capture)工具**:这些工具可以从数据库的日志中提取变化的数据,并将其传输到目标系统。 3. **第方中间件或框架**:例如 DebeziumMaxwellCanal 等,虽然它们主要用于 MySQL 和 PostgreSQL,但也有一些针对 Oracle 的适配方案。 --- #### 推荐的开源免费框架 ##### 1. **Debezium** Debezium 是一个分布式平台,用于捕获数据库中的变更并通过消息队列(如 Kafka)发布这些变更。对于 Oracle 数据库的支持,Debezium 提供了专门的连接器,可以通过解析重做日志(Redo Logs)来捕捉数据的变化[^6]。 ```java // 配置 Debezium 连接器以监听 Oracle 数据库 Properties props = new Properties(); props.setProperty("connector.class", "io.debezium.connector.oracle.OracleConnector"); props.setProperty("database.server.name", "my-oracle-server"); props.setProperty("database.hostname", "localhost"); props.setProperty("database.port", "1521"); props.setProperty("database.user", "debezium"); props.setProperty("database.password", "dbz"); props.setProperty("database.dbname", "ORCLPDB1"); props.setProperty("table.whitelist", "MYSCHEMA.MYTABLE"); ``` 尽管 Debezium 不直接支持 ASM 日志的解析,但它可以间接通过 Oracle 的 Redo Logs 获取所需的信息。 ##### 2. **LogMiner** Oracle 自身提供的 LogMiner 工具允许开发者访问重做日志的内容,并从中提取 DML 和 DDL 操作的详细信息。虽然这不是一个独立的开源框架,但其功能可以通过自定义脚本封装为轻量级的应用程序[^7]。 ```sql -- 启动 LogMiner 并指定要解析的日志范围 EXECUTE DBMS_LOGMNR.START_LOGMNR( OPTIONS => DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG + DBMS_LOGMNR.COMMITTED_DATA_ONLY); SELECT SCN, OPERATION, SQL_REDO FROM V$LOGMNR_CONTENTS; ``` ##### 3. **DBSyncer** DBSyncer 是一款专注于增量同步的开源框架,特别适合基于 Oracle 通知机制的场景[^1]。该框架的核心优势在于其实现了高效的双向同步能力,但由于其依赖于触发器或其他显式的变更捕获方式,可能无法完全满足对 ASM 日志实时需求。 ##### 4. **GoldenGate Community Edition** 虽然 GoldenGate 官方版本并非完全免费,但在某些特定条件下,社区版仍然可供试用。作为业界领先的 CDC 解决方案之一,GoldenGate 支持从 ASM 存储层读取重做日志并完成跨系统的数据复制[^8]。 --- #### 技术选型建议 如果项目预算有限且追求纯粹的开源实现,则推荐优先考虑 **Debezium** 或者自行封装 **LogMiner** 功能;而对于更复杂的企业级需求而言,评估引入 **GoldenGate 社区版** 的可行性可能是更好的选择。 --- ###
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王义凯_Rick

遇见即是缘,路过就给个评论吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值