使用Docker部署debezium来监控 MySQL 数据库

使用Docker部署debezium来监控 MySQL 数据库

Debezium是一个分布式平台,它将来自现有数据库的信息转换为事件流,使应用程序能够检测并立即响应数据库中的行级更改。

Debezium构建在Apache Kafka之上,并提供了一组Kafka Connect兼容的连接器。每个连接器都与特定的数据库管理系统(DBMS)一起工作。连接器通过检测发生的变化来记录DBMS中数据变化的历史,并将每个变化事件的记录流式传输到Kafka topic。然后,消费应用程序可以从Kafka topic中读取结果事件记录。

通过利用Kafka可靠的流平台,Debezium使应用程序能够正确和完整地消费数据库中发生的更改。即使您的应用程序意外停止或失去连接,它也不会错过停机期间发生的事件。应用程序重新启动后,它将从停止的位置继续从topic读取。

debezium 包含了下面这些连接器:

  • Debezium connector for Cassandra
  • Debezium connector for Db2
  • Debezium connector for MongoDB
  • Debezium connector for MySQL
  • Debezium connector for Oracle Database
  • Debezium connector for PostgreSQL
  • Debezium connector for SQL Server
  • Debezium connector for Vitess

下面我们将使用docker部署一个debezium mysql connector,来监控 MySQL数据库的变化。

1.准备工作

安装并启动 docker,如果还没有安装,可以参考:官方安装指南


2.启动服务

使用Debezium需要三个独立的服务:ZooKeeperKafkaDebezium connector。在本教程中,我们将使用DockerDebezium提供的容器镜像来启动每个服务。

为了减少服务启动所需的资源,以及简化操作步骤和配置,我们都将以单机的方式来启动 zookeeper 和 kafka。

为了在使用完容器之后能够更容易的清除数据,我们在启动容器的时候不进行卷挂载,这样容器停止的时候所保存的数据都会丢失。

并且,为了能够实时看到容器输出,我们将不使用-d的方式在后台启动,而是将容器的所有输出都显示在启动它的终端,并且每个启动的服务都将有一个独立的终端。

2.1 启动 zookeeper

ZooKeeper是第一个必须启动的服务。

步骤:

(1)使用1.9 版本的quay.io/debezium/zookeeper镜像运行一个新容器

docker run -it --rm --name zookeeper -p 2181:2181 -p 2888:2888 -p 3888:3888 quay.io/debezium/zookeeper:1.9

命令解析:

  • -it:容器是交互式的,这意味着终端的标准输入和输出附加到容器上。
  • --rm:容器停止时将被移除。
  • --name zookeeper:指定容器的名称为 zookeeper。
  • -p 2181:2181 -p 2888:2888 -p 3888:3888:将容器的三个端口映射到Docker主机上的相同端口,这样其他容器(以及容器外的应用程序)才能够与ZooKeeper通信。

(2)验证ZooKeeper是否启动。

如果看到类似以下的输出,就说明 zookeeper 已经成功启动。

Starting up in standalone mode
/usr/bin/java
ZooKeeper JMX enabled by default
Using config: /zookeeper/conf/zoo.cfg
...
port 0.0.0.0/0.0.0.0:2181

2.2 启动 kafka

启动ZooKeeper后,接下来我们在一个新的容器中启动Kafka

步骤:

(1)使用1.9版本的quay.io/debezium/kafka镜像运行一个新容器:

docker run -it --rm --name kafka -p 9092:9092 --link zookeeper:zookeeper quay.io/debezium/kafka:1.9

命令解析:

  • -it:容器是交互式的,这意味着终端的标准输入和输出都附加在容器上。
  • --rm:容器停止时将被移除。
  • --name kafka:指定容器名称为kafka。
  • -p 9092:9092:将容器中的9092端口映射到Docker主机上的相同端口,以便容器外的应用程序可以与Kafka通信。
  • --link zookeeper:zookeeper:告诉容器它可以在zookeeper容器中找到zookeeper,该容器在同一目录下运行。

(2)验证kafka是否启动。

如果看到类似以下的输出,则说明 kafka 已经成功启动。

Starting in ZooKeeper mode using NODE_ID=1.
Using ZOOKEEPER_CONNECT=172.17.0.2:2181
Using configuration config/server.properties.
Using KAFKA_LISTENERS=PLAINTEXT://172.17.0.4:9092 and KAFKA_ADVERTISED_LISTENERS=PLAINTEXT://172.17.0.4:9092
2023-09-02 16:43:50,944 - INFO  [main:Log4jControllerRegistration$@31] - Registered kafka:type=kafka.Log4jController MBean
2023-09-02 16:43:51,682 - INFO  [main:X509Util@77] - Setting -D jdk.tls.rejectClientInitiatedRenegotiation=true to disable client-initiated TLS renegotiation
2023-09-02 16:43:52,032 - INFO  [main:LoggingSignalHandler@72] - Registered signal handlers for TERM, INT, HUP
2023-09-02 16:43:52,047 - INFO  [main:Logging@66] - starting
2023-09-02 16:43:52,050 - INFO  [main:Logging@66] - Connecting to zookeeper on 172.17.0.2:2181
2023-09-02 16:43:52,109 - INFO  [main:Logging@66] - [ZooKeeperClient Kafka server] Initializing a new session to 172.17.0.2:2181.
...
2023-09-02 16:43:56,541 - INFO  [main:AppInfoParser$AppInfo@119] - Kafka version: 3.2.0
2023-09-02 16:43:56,542 - INFO  [main:AppInfoParser$AppInfo@120] - Kafka commitId: 38103ffaa962ef50
2023-09-02 16:43:56,542 - INFO  [main:AppInfoParser$AppInfo@121] - Kafka startTimeMs: 1693673036411
2023-09-02 16:43:56,578 - INFO  [main:Logging@66] - [KafkaServer id=1] started

[KafkaServer id=1] started表示 kafka 已经成功启动,并为客户端连接做好准备。


2.3 启动 MySQL

此时我们已经启动了ZooKeeperKafka,现在需要启动一个 MySQL 数据库服务。我们将使用一个示例数据库启动MySQL服务器。

步骤:

(1)打开一个新的终端,使用下面的命令启动一个新的容器,该容器运行预先配置了inventory数据库的MySQL数据库服务器。

该命令使用1.9版本的quay.io/debezium/example-mysql镜像运行一个新容器。基于mysql:8.0镜像。它还定义并填充了一个inventory数据库。

docker run -it --rm --name mysql -p 3306:3306 \ 
-e MYSQL_ROOT_PASSWORD=debezium -e MYSQL_USER=mysqluser -e MYSQL_PASSWORD=mysqlpw \
quay.io/debezium/example-mysql:1.9

命令解析:

  • -it:容器是交互式的,这意味着终端的标准输入和输出都附加在容器上。
  • --rm:容器停止时将被移除。
  • --name mysql:指定容器名称为mysql。
  • -p 3306:3306:将容器中的3306端口(MySQL的默认端口)映射到Docker主机上的相同端口,以便容器外的应用程序可以与启动的MySQL服务通信。
  • -e MYSQL_ROOT_PASSWORD=debezium -e MYSQL_USER=mysqluser -e MYSQL_PASSWORD=mysqlpw:创建具有Debezium MySQL连接器所需的最低权限的用户和密码。

(2)验证

如果看到类似下面的输出,说明 MySQL 服务已经正常启动。

...
2023-09-02T16:37:34.067920Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
2023-09-02T16:37:34.068725Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.31'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.

然后就可以通过 mysql 连接工具来连接本地启动的 mysql 服务了,也可以执行类似use inventory; show tables; select * from customers;这些 SQL 语句来查看当前 mysql 的已有的表和数据了。


2.4 启动 kafka connect

现在可以启动 Kafka Connect 服务,它公开了一个REST API来管理Debezium MySQL连接器。

步骤:

(1)开启一个新的终端,使用镜像 quay.io/debezium/connect:2.3 来运行一个新的容器。

docker run -it --rm --name connect -p 8083:8083 \
-e GROUP_ID=1 \
-e CONFIG_STORAGE_TOPIC=my_connect_configs \
-e OFFSET_STORAGE_TOPIC=my_connect_offsets \
-e STATUS_STORAGE_TOPIC=my_connect_statuses \
--link kafka:kafka --link mysql:mysql \
quay.io/debezium/connect:2.3

命令解析:

  • --name connect:指定启动的容器名称
  • -p 8083:8083 :将容器中的8083端口映射到Docker主机上的相同端口。这使得容器外的应用程序可以使用Kafka ConnectREST API来设置和管理新的容器实例。
  • -e GROUP_ID=1 -e CONFIG_STORAGE_TOPIC=my_connect_configs -e OFFSET_STORAGE_TOPIC=my_connect_offsets -e STATUS_STORAGE_TOPIC=my_connect_statuses :设置镜像所需的环境变量
  • --link kafka:kafka --link mysql:mysql:将容器链接到正在运行的 KafkaMySQL 容器。

(2)验证

如果看到类似下面的输出,则说明启动成功。

...
2023-09-04 16:48:33,939 INFO   ||  Kafka version: 3.4.0   [org.apache.kafka.common.utils.AppInfoParser]
...
2023-09-04 16:48:34,485 INFO   ||  [Worker clientId=connect-1, groupId=1] Starting connectors and tasks using config offset -1   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
2023-09-04 16:48:34,485 INFO   ||  [Worker clientId=connect-1, groupId=1] Finished starting connectors and tasks   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]

下面我们使用 Kafka Connect REST API 来检查 Kafka Connect 服务的状态。

打开一个新的终端,执行如下命令:

curl -H "Accept:application/json" localhost:8083/
{"version":"3.4.0","commit":"cb8625948210849f"}  

表明Kafka Connect版本3.4.0正在运行。

接下来我们查看以下 Kafka Connect 中注册的连接器列表:

curl -H "Accept:application/json" localhost:8083/connectors/
[]

表明 Kafka Connect 目前没有注册连接器。


3. 部署 MySQL 连接器

3.1 注册MySQL连接器来监控数据库

现在 Kafka Connect服务中没有注册的连接器,我们现在开始注册一个 Debezium MySQL Connector,来监视 inventory 数据库中数据表的变化。对于 MySQL 数据库来说,Debezium MySQL Connector通过监听源数据表的 binlog 来获取数据库所有的变更事件。

对于 MySQL 数据库来说,binlog记录了数据库的所有事务(例如对单个行的更改和对模式的更改)。当数据库中的一行发生更改时,Debezium生成一个更改事件。

在生产环境中,通常要么使用Kafka工具手动创建topic,在创建的时候指定分区和副本的数量,要么使用Kafka Connect机制自定义自动创建主题的设置。在本教程中,Kafka被配置为只使用一个副本自动创建 topic

步骤:

(1)准备将要注册的Debezium MySQL连接器的配置。

我们要注册的连接器的配置如下:

{
  "name": "inventory-connector",  
  "config": {  
    "connector.class": "io.debezium.connector.mysql.MySqlConnector",
    "tasks.max": "1",  
    "database.hostname": "mysql",  
    "database.port": "3306",
    "database.user": "root",
    "database.password": "debezium",
    "database.server.id": "184054",  
    "database.server.name": "dbserver1",  
    "database.include.list": "inventory",  
    "database.history.kafka.bootstrap.servers": "kafka:9092",  
    "database.history.kafka.topic": "schema-changes.inventory"  
  }
}

配置说明:

  • "name": "inventory-connector":连接器的名称
  • "config":连接器的配置
  • "tasks.max": "1":任何时候只能操作一个任务。因为MySQL连接器读取MySQL服务器的binlog,所以使用单个连接器任务可以确保正确的顺序和事件处理。Kafka Connect服务使用连接器来启动一个或多个完成工作的任务,并自动将正在运行的任务分布到Kafka Connect服务的集群中。如果任何服务停止或崩溃,这些任务将被重新分配给正在运行的服务。
  • "database.hostname": "mysql":数据库主机,即MySQL服务器所在的Docker容器的名称。Docker操作容器中的网络堆栈,这样每个链接的容器都可以用/etc/hosts来解析,使用容器名作为主机名。如果MySQL运行在一个正常的网络上,可以为这个值指定IP地址或可解析的主机名。
  • "database.server.id": "184054", "database.server.name": "dbserver1":唯一的服务器ID和名称。服务器名称是MySQL服务器或服务器集群的逻辑标识符。这个名字将被用作所有Kafka topic的前缀。
  • "database.include.list": "inventory":指定要监听的数据库的范围,只会检测到 inventory 数据库中的更改。
  • “database.history.kafka.bootstrap.servers“:指定存储数据库历史 schema 信息所使用的 kafka 服务。
  • ”database.history.kafka.topic”:指定 kafka 存储数据库历史 schema 信息所使用的 kafka topic 名称。

出于安全考虑,不应该将纯文本形式的密码或其他秘密放入连接器配置中。

(2)打开一个新的终端,并使用curl命令注册Debezium MySQL连接器。

该命令使用Kafka Connect服务的API/connectors资源提交POST请求,并使用描述新连接器(称为inventory-connector)的JSON文档。该命令使用localhost连接到Docker主机。如果您使用的是非本地Docker平台,请将localhost替换为您的Docker主机的IP地址。

curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" localhost:8083/connectors/ \
-d '{ "name": "inventory-connector", "config": { "connector.class": "io.debezium.connector.mysql.MySqlConnector", "tasks.max": "1", "database.hostname": "mysql", "database.port": "3306", "database.user": "root", "database.password": "debezium", "database.server.id": "184054", "database.server.name": "dbserver1", "database.include.list": "inventory", "database.history.kafka.bootstrap.servers": "kafka:9092", "database.history.kafka.topic": "dbhistory.inventory" } }'

(3)验证inventory-connector是否包含在连接器列表中:

curl -H "Accept:application/json" localhost:8083/connectors/
["inventory-connector"]

(4)查看连接器的任务:

curl -i -X GET -H "Accept:application/json" localhost:8083/connectors/inventory-connector

应该看到类似于以下的响应(为便于阅读而格式化):

HTTP/1.1 200 OK
Date: Thu, 06 Feb 2020 22:12:03 GMT
Content-Type: application/json
Content-Length: 531
Server: Jetty(9.4.20.v20190813)

{
  "name": "inventory-connector",
  ...
  "tasks": [
    {
      "connector": "inventory-connector",  
      "task": 0
    }
  ]
}

连接器运行单个任务(任务0)来完成其工作。连接器只支持单个任务,因为MySQL将其所有活动记录在一个顺序的binlog中。这意味着连接器只需要一个读取器就可以获得所有事件的一致姓有序视图。

3.2 观察连接器启动

当我们注册一个新的连接器时,kafka connect容器中会生成大量日志,通过查看这些日志我们可以理解连接器从创建到开始读取 MySQL 服务器的 binlog 所经历的过程。

默认情况下,会首先创建和启动连接器 inventory-connector

...
2021-11-30 01:38:44,223 INFO   ||  [Worker clientId=connect-1, groupId=1] Tasks [inventory-connector-0] configs updated   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
2021-11-30 01:38:44,224 INFO   ||  [Worker clientId=connect-1, groupId=1] Handling task config update by restarting tasks []   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
2021-11-30 01:38:44,224 INFO   ||  [Worker clientId=connect-1, groupId=1] Rebalance started   [org.apache.kafka.connect.runtime.distributed.WorkerCoordinator]
2021-11-30 01:38:44,224 INFO   ||  [Worker clientId=connect-1, groupId=1] (Re-)joining group   [org.apache.kafka.connect.runtime.distributed.WorkerCoordinator]
2021-11-30 01:38:44,227 INFO   ||  [Worker clientId=connect-1, groupId=1] Successfully joined group with generation Generation{generationId=3, memberId='connect-1-7b087c69-8ac5-4c56-9e6b-ec5adabf27e8', protocol='sessioned'}   [org.apache.kafka.connect.runtime.distributed.WorkerCoordinator]
2021-11-30 01:38:44,230 INFO   ||  [Worker clientId=connect-1, groupId=1] Successfully synced group in generation Generation{generationId=3, memberId='connect-1-7b087c69-8ac5-4c56-9e6b-ec5adabf27e8', protocol='sessioned'}   [org.apache.kafka.connect.runtime.distributed.WorkerCoordinator]
2021-11-30 01:38:44,231 INFO   ||  [Worker clientId=connect-1, groupId=1] Joined group at generation 3 with protocol version 2 and got assignment: Assignment{error=0, leader='connect-1-7b087c69-8ac5-4c56-9e6b-ec5adabf27e8', leaderUrl='http://172.17.0.7:8083/', offset=4, connectorIds=[inventory-connector], taskIds=[inventory-connector-0], revokedConnectorIds=[], revokedTaskIds=[], delay=0} with rebalance delay: 0   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
2021-11-30 01:38:44,232 INFO   ||  [Worker clientId=connect-1, groupId=1] Starting connectors and tasks using config offset 4   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
2021-11-30 01:38:44,232 INFO   ||  [Worker clientId=connect-1, groupId=1] Starting task inventory-connector-0   [org.apache.kafka.connect.runtime.distributed.DistributedHerder]
...

接下来,连接器开始执行快照,即对读取存量并写入 kafka topic:

...
2021-11-30 01:38:44,534 INFO   MySQL|dbserver1|snapshot  Snapshot step 1 - Preparing   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:44,535 INFO   MySQL|dbserver1|snapshot  Snapshot step 2 - Determining captured tables   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:44,535 INFO   MySQL|dbserver1|snapshot  Read list of available databases   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,537 INFO   MySQL|dbserver1|snapshot  	 list of available databases is: [information_schema, inventory, mysql, performance_schema, sys]   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,537 INFO   MySQL|dbserver1|snapshot  Read list of available tables in each database   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,548 INFO   MySQL|dbserver1|snapshot  	snapshot continuing with database(s): [inventory]   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,551 INFO   MySQL|dbserver1|snapshot  Snapshot step 3 - Locking captured tables [inventory.addresses, inventory.customers, inventory.geom, inventory.orders, inventory.products, inventory.products_on_hand]   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:44,552 INFO   MySQL|dbserver1|snapshot  Flush and obtain global read lock to prevent writes to database   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,557 INFO   MySQL|dbserver1|snapshot  Snapshot step 4 - Determining snapshot offset   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:44,560 INFO   MySQL|dbserver1|snapshot  Read binlog position of MySQL primary server   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,562 INFO   MySQL|dbserver1|snapshot  	 using binlog 'mysql-bin.000003' at position '156' and gtid ''   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:44,562 INFO   MySQL|dbserver1|snapshot  Snapshot step 5 - Reading structure of captured tables   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:44,562 INFO   MySQL|dbserver1|snapshot  All eligible tables schema should be captured, capturing: [inventory.addresses, inventory.customers, inventory.geom, inventory.orders, inventory.products, inventory.products_on_hand]   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:45,058 INFO   MySQL|dbserver1|snapshot  Reading structure of database 'inventory'   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:45,187 INFO   MySQL|dbserver1|snapshot  Snapshot step 6 - Persisting schema history   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,273 INFO   MySQL|dbserver1|snapshot  Releasing global read lock to enable MySQL writes   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:45,274 INFO   MySQL|dbserver1|snapshot  Writes to MySQL tables prevented for a total of 00:00:00.717   [io.debezium.connector.mysql.MySqlSnapshotChangeEventSource]
2021-11-30 01:38:45,274 INFO   MySQL|dbserver1|snapshot  Snapshot step 7 - Snapshotting data   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,275 INFO   MySQL|dbserver1|snapshot  Snapshotting contents of 6 tables while still in transaction   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,275 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.addresses' (1 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,276 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.addresses' using select statement: 'SELECT `id`, `customer_id`, `street`, `city`, `state`, `zip`, `type` FROM `inventory`.`addresses`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,295 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 7 records for table 'inventory.addresses'; total duration '00:00:00.02'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,296 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.customers' (2 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,296 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.customers' using select statement: 'SELECT `id`, `first_name`, `last_name`, `email` FROM `inventory`.`customers`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,304 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 4 records for table 'inventory.customers'; total duration '00:00:00.008'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,304 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.geom' (3 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,305 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.geom' using select statement: 'SELECT `id`, `g`, `h` FROM `inventory`.`geom`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,316 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 3 records for table 'inventory.geom'; total duration '00:00:00.011'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,316 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.orders' (4 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,316 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.orders' using select statement: 'SELECT `order_number`, `order_date`, `purchaser`, `quantity`, `product_id` FROM `inventory`.`orders`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,325 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 4 records for table 'inventory.orders'; total duration '00:00:00.008'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,325 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.products' (5 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,325 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.products' using select statement: 'SELECT `id`, `name`, `description`, `weight` FROM `inventory`.`products`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,343 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 9 records for table 'inventory.products'; total duration '00:00:00.017'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,344 INFO   MySQL|dbserver1|snapshot  Exporting data from table 'inventory.products_on_hand' (6 of 6 tables)   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,344 INFO   MySQL|dbserver1|snapshot  	 For table 'inventory.products_on_hand' using select statement: 'SELECT `product_id`, `quantity` FROM `inventory`.`products_on_hand`'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,353 INFO   MySQL|dbserver1|snapshot  	 Finished exporting 9 records for table 'inventory.products_on_hand'; total duration '00:00:00.009'   [io.debezium.relational.RelationalSnapshotChangeEventSource]
2021-11-30 01:38:45,355 INFO   MySQL|dbserver1|snapshot  Snapshot - Final stage   [io.debezium.pipeline.source.AbstractSnapshotChangeEventSource]
2021-11-30 01:38:45,356 INFO   MySQL|dbserver1|snapshot  Snapshot ended with SnapshotResult [status=COMPLETED, offset=MySqlOffsetContext [sourceInfoSchema=Schema{io.debezium.connector.mysql.Source:STRUCT}, sourceInfo=SourceInfo [currentGtid=null, currentBinlogFilename=mysql-bin.000003, currentBinlogPosition=156, currentRowNumber=0, serverId=0, sourceTime=2021-11-30T01:38:45.352Z, threadId=-1, currentQuery=null, tableIds=[inventory.products_on_hand], databaseName=inventory], snapshotCompleted=true, transactionContext=TransactionContext [currentTransactionId=null, perTableEventCount={}, totalEventCount=0], restartGtidSet=null, currentGtidSet=null, restartBinlogFilename=mysql-bin.000003, restartBinlogPosition=156, restartRowsToSkip=0, restartEventsToSkip=0, currentEventLengthInBytes=0, inTransaction=false, transactionId=null, incrementalSnapshotContext =IncrementalSnapshotContext [windowOpened=false, chunkEndPosition=null, dataCollectionsToSnapshot=[], lastEventKeySent=null, maximumKey=null]]]   [io.debezium.pipeline.ChangeEventSourceCoordinator]
...

从上述日志可以看到,执行快照的步骤如下:
第一步:准备阶段;
第二步:根据配置决定要对哪些表执行快照
第三步:对要执行快照的表加锁;
第四步:决定读取快照的偏移量;
第五步:读取要执行快照的数据表的表结构信息,用于解析
第六步:释放全局读锁,持久化第五步读取到的表结构信息
第七步:对要做快照的数据表依次做快照

最后,日志输出显示连接器已经从快照模式转变为连续读取MySQL服务器的binlog,即开始读取新增数据:

...
2021-11-30 01:38:45,362 INFO   MySQL|dbserver1|streaming  Starting streaming   [io.debezium.pipeline.ChangeEventSourceCoordinator]
...
Nov 30, 2021 1:38:45 AM com.github.shyiko.mysql.binlog.BinaryLogClient connect
INFO: Connected to mysql:3306 at mysql-bin.000003/156 (sid:184054, cid:13)
2021-11-30 01:38:45,392 INFO   MySQL|dbserver1|binlog  Connected to MySQL binlog at mysql:3306, starting at MySqlOffsetContext [sourceInfoSchema=Schema{io.debezium.connector.mysql.Source:STRUCT}, sourceInfo=SourceInfo [currentGtid=null, currentBinlogFilename=mysql-bin.000003, currentBinlogPosition=156, currentRowNumber=0, serverId=0, sourceTime=2021-11-30T01:38:45.352Z, threadId=-1, currentQuery=null, tableIds=[inventory.products_on_hand], databaseName=inventory], snapshotCompleted=true, transactionContext=TransactionContext [currentTransactionId=null, perTableEventCount={}, totalEventCount=0], restartGtidSet=null, currentGtidSet=null, restartBinlogFilename=mysql-bin.000003, restartBinlogPosition=156, restartRowsToSkip=0, restartEventsToSkip=0, currentEventLengthInBytes=0, inTransaction=false, transactionId=null, incrementalSnapshotContext =IncrementalSnapshotContext [windowOpened=false, chunkEndPosition=null, dataCollectionsToSnapshot=[], lastEventKeySent=null, maximumKey=null]]   [io.debezium.connector.mysql.MySqlStreamingChangeEventSource]
2021-11-30 01:38:45,392 INFO   MySQL|dbserver1|streaming  Waiting for keepalive thread to start   [io.debezium.connector.mysql.MySqlStreamingChangeEventSource]
2021-11-30 01:38:45,393 INFO   MySQL|dbserver1|binlog  Creating thread debezium-mysqlconnector-dbserver1-binlog-client   [io.debezium.util.Threads]
...

4. 数据库变更事件

当我们成功部署Debezium MySQL连接器之后,它就开始监视 inventory 数据库中的数据表,并将数据更改事件写入对应的 kafka topic。在这个例子中,我们配置了下面这些 kafka topic

  • dbserver1: 捕获 MySQL 服务器所有的 DDL 语句。
  • dbserver1.inventory.products: 捕获 inventory.products 表的更改事件。
  • dbserver1.inventory.products_on_hand: 捕获 inventory.products_on_hand 表的更改事件。
  • dbserver1.inventory.customers: 捕获 inventory.customers 表的更改事件。
  • dbserver1.inventory.orders: 捕获 inventory.orders 表的更改事件。

下面我们将修改inventory.customers 表的数据,并且在观察 dbserver1.inventory.customers topic

4.1 create 事件

inventory.customers表插入一条数据,观察可以发现dbserver1.inventory.customers中增加了一条消息。

4.2 update 事件

inventory.customers表更新一条数据,观察可以发现dbserver1.inventory.customers中增加了一条消息。

4.3 delete 事件

inventory.customers表删除一条数据,观察可以发现dbserver1.inventory.customers中增加了一条消息。

5. 资源清理

使用下面的命令停止启动的 docker 容器。

docker stop connect mysql kafka zookeeper
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值