Debezium发布历史32

原文地址: https://debezium.io/blog/2018/05/24/querying-debezium-change-data-eEvents-with-ksql/

欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯.

使用 KSQL 查询 Debezium 更改数据事件

五月 24, 2018 作者: Jiri Pechanec

mysql ksql 示例

最后更新于 2018 年 11 月 21 日(调整为新的 KSQL Docker 映像)。

去年,我们见证了Apache Kafka领域中一个新的开源项目KSQL的启动,它是一个构建在Kafka Streams之上的流式 SQL 引擎。在这篇文章中,我们将尝试使用 Debezium 从 MySQL 数据库生成的数据更改事件进行 KSQL 查询。

作为数据源,我们将使用教程中的数据库和设置。此练习的结果应该类似于最近关于将事件聚合到域驱动聚合中的帖子。

实体图

首先让我们看一下数据库中的实体以及它们之间的关系。

图片来自于官网

图 1:示例实体的实体图

上图显示了示例 MySQL 实例中库存数据库的完整 ER 图。我们将重点关注两个实体:

customers- 系统中的客户列表

orders- 系统中的订单列表

和之间存在1:n关系,由表中的列建模,该列是表的外键。customersorderspurchaserorderscustomers

配置

我们将使用Docker Compose 文件来部署环境。该部署由以下 Docker 映像组成:

阿帕奇动物园管理员

阿帕奇·卡夫卡

Kafka Connect 包括 Debezium 连接器镜像

我们的教程中使用的预填充 MySQL 数据库

KSQL 服务器和CLI客户端

例子

首先我们需要启动 Debezium 和 Kafka 基础设施。为此,请克隆debezium-examples GitHub 存储库并使用提供的 Compose 文件启动所需的组件:

export DEBEZIUM_VERSION=0.8

git clone https://github.com/debezium/debezium-examples.git

cd debezium-examples/ksql/

docker-compose up

接下来我们必须注册 Debezium MySQL 连接器的实例来监听数据库中的更改:

curl -i -X POST -H "Accept:application/json" -H "Content-Type:application/json" http://localhost:8083/connectors/ -d @- <<-EOF

{

"name": "inventory-connector",

"config": {

"connector.class": "io.debezium.connector.mysql.MySqlConnector",

"tasks.max": "1",

"database.hostname": "mysql",

"database.port": "3306",

"database.user": "debezium",

"database.password": "dbz",

"database.server.id": "184055",

"database.server.name": "dbserver",

"database.whitelist": "inventory",

"database.history.kafka.bootstrap.servers": "kafka:9092",

"database.history.kafka.topic": "schema-changes.inventory",

"transforms": "unwrap",

"transforms.unwrap.type": "io.debezium.transforms.UnwrapFromEnvelope",

"key.converter": "org.apache.kafka.connect.json.JsonConverter",

"key.converter.schemas.enable": "false",

"value.converter": "org.apache.kafka.connect.json.JsonConverter",

"value.converter.schemas.enable": "false"

}

}

EOF

现在我们应该让所有组件启动并运行,并且初始数据更改事件已经流入 Kafka 主题。有多个属性对于我们的用例特别重要:

使用UnwrapFromEnvelope SMT 。这允许我们直接将部分after变更记录中的字段映射到KSQL语句中。如果没有它,我们将需要使用从消息部分EXTRACTJSONFIELD中提取的每个字段。after

JSON 转换器禁用架构。原因与上面相同。启用模式后,对于 JSON,记录封装在包含字段schema(带有模式信息)和payload(带有实际数据本身)的 JSON 结构中。我们将再次需要使用EXTRACTJSONFIELD来访问相关字段。Avro转换器不存在此问题,因此使用Avro时无需设置此选项。

接下来我们将启动 KSQL 命令 shell。我们将在 CLI 中运行本地引擎。另请注意--net参数。这保证了 KSQL 容器与 Debezium 容器在同一网络中运行,并允许正确的 DNS 解析。

docker-compose exec ksql-cli ksql http://ksql-server:8088

首先,我们将列出代理中存在的所有 Kafka 主题:

ksql> LIST TOPICS;

Kafka Topic | Registered | Partitions | Partition Replicas

connect-status | false | 5 | 1

dbserver | false | 1 | 1

dbserver.inventory.addresses | false | 1 | 1

dbserver.inventory.customers | false | 1 | 1

dbserver.inventory.orders | false | 1 | 1

dbserver.inventory.products | false | 1 | 1

dbserver.inventory.products_on_hand | false | 1 | 1

ksql__commands | true | 1 | 1

my_connect_configs | false | 1 | 1

my_connect_offsets | false | 25 | 1

schema-changes.inventory | false | 1 | 1

我们感兴趣的主题是dbserver.inventory.orders和dbserver.inventory.customers。

默认情况下,KSQL 处理从偏移量开始latest。我们想要处理主题中已有的事件,因此我们从earliest偏移量切换处理。

ksql> SET 'auto.offset.reset' = 'earliest';

Successfully changed local property 'auto.offset.reset' from 'null' to 'earliest'

首先,我们需要从包含 Debezium 数据更改事件的主题创建流。KSQL 和 Kafka Streams 术语中的流是没有状态的无限传入数据集。

ksql> CREATE STREAM orders_from_debezium (order_number integer, order_date string, purchaser integer, quantity integer, product_id integer) WITH (KAFKA_TOPIC='dbserver.inventory.orders',VALUE_FORMAT='json');

Message

Stream created

ksql>

ksql> CREATE STREAM customers_from_debezium (id integer, first_name string, last_name string, email string) WITH (KAFKA_TOPIC='dbserver.inventory.customers',VALUE_FORMAT='json');

Message

Stream created

分区

我们的部署每个主题仅使用一个分区。在生产系统中,每个主题可能有多个分区,我们需要确保属于聚合对象的所有事件最终都位于同一分区中。在我们的例子中,自然分区是按客户 ID 进行的。我们将orders_from_debezium根据purchaser包含客户 ID 的字段对流进行重新分区。重新分区后的数据被写入新的主题中ORDERS_REPART:

ksql> CREATE STREAM orders WITH (KAFKA_TOPIC='ORDERS_REPART',VALUE_FORMAT='json',PARTITIONS=1) as SELECT * FROM orders_from_debezium PARTITION BY PURCHASER;

Message

Stream created and running

ksql> LIST TOPICS;

Kafka Topic | Registered | Partitions | Partition Replicas

...

ORDERS_REPART | true | 1 | 1

...

我们也将为客户执行相同的操作。这是必要的,原因有两个:

当前键是一个结构体,其中包含一个id以客户 ID 命名的字段。这与重新分区的订单主题不同,后者仅包含id值作为键,因此分区不会匹配。

当我们稍后创建 JOIN 时,有一个限制,要求键与表中的键字段具有相同的值。表字段包含一个普通值,但键包含一个结构,因此它们不匹配。有关更多详细信息,请参阅此 KSQL 问题。

ksql> CREATE STREAM customers_stream WITH (KAFKA_TOPIC='CUSTOMERS_REPART',VALUE_FORMAT='json',PARTITIONS=1) as SELECT * FROM customers_from_debezium PARTITION BY ID;

Message

Stream created and running

ksql> LIST TOPICS;

Kafka Topic | Registered | Partitions | Partition Replicas

...

CUSTOMERS_REPART | true | 1 | 1

...

为了验证记录是否具有新密钥并因此重新分区,我们可以发出一些语句来比较结果:

ksql> SELECT * FROM orders_from_debezium LIMIT 1;

1524034842810 | {"order_number":10001} | 10001 | 16816 | 1001 | 1 | 102

LIMIT reached for the partition.

Query terminated

ksql> SELECT * FROM orders LIMIT 1;

1524034842810 | 1001 | 10001 | 16816 | 1001 | 1 | 102

LIMIT reached for the partition.

Query terminated

第二列包含ROWKEY消息的关键字。

客户/订单加盟

到目前为止,我们仅将流声明为无界无状态数据集。在我们的用例中,这order实际上是一个来来去去的事件。但是customer是一个可以更新的实体,通常是系统状态的一部分。这种质量在 KSQL 或 Kafka Streams 中以表的形式表示。我们将从包含重新分区客户的主题创建一个客户表。

ksql> CREATE TABLE customers (id integer, first_name string, last_name string, email string) WITH (KAFKA_TOPIC='CUSTOMERS_REPART',VALUE_FORMAT='json',KEY='id');

Message

Table created

现在,我们已准备就绪,可以在客户及其订单之间进行联接,并创建一个查询来监视传入订单并将其与关联的客户字段一起列出。

ksql> SELECT order_number,quantity,customers.first_name,customers.last_name FROM orders left join customers on orders.purchaser=customers.id;

10001 | 1 | Sally | Thomas

10002 | 2 | George | Bailey

10003 | 2 | George | Bailey

10004 | 1 | Edward | Walker

让我们对数据库进行一些更改,这将导致 Debezium 发出相应的 CDC 事件:

docker-compose exec mysql bash -c 'mysql -u M Y S Q L U S E R − p MYSQL_USER -p MYSQLUSER−pMYSQL_PASSWORD inventory'

mysql> INSERT INTO orders VALUES(default,NOW(), 1003,5,101);

Query OK, 1 row affected, 1 warning (0.02 sec)

mysql> UPDATE customers SET first_name='Annie' WHERE id=1004;

Query OK, 1 row affected (0.02 sec)

Rows matched: 1 Changed: 1 Warnings: 0

mysql> UPDATE orders SET quantity=20 WHERE order_number=10004;

Query OK, 1 row affected (0.02 sec)

Rows matched: 1 Changed: 1 Warnings: 0

您可能会注意到,只有orders表中的更改才会触发连接流中的更改。这是流/表连接的产物。如果任何输入流被修改,我们将需要一个流/流连接来触发更改。

所以数据库修改后select的最终结果是

10001 | 1 | Sally | Thomas

10002 | 2 | George | Bailey

10003 | 2 | George | Bailey

10004 | 1 | Edward | Walker

10005 | 5 | Edward | Walker

10004 | 20 | Edward | Walker

概括

我们已经成功启动了一个KSQL实例。我们已将 KSQL 流映射到 Debezium 填充的 Debezium 主题,并在它们之间建立连接。我们还讨论了流应用程序中的重新分区问题。

如果您想使用 Avro 编码和模式注册表尝试此示例,那么您可以使用我们的Avro 示例。另外,有关更多详细信息和更高级的用法,请参阅 KSQL语法参考。

如果您需要帮助、有功能请求或想分享您对此示例的体验,请在下面的评论中告诉我们。

相关推荐
数据智能老司机7 小时前
CockroachDB权威指南——CockroachDB SQL
数据库·分布式·架构
数据智能老司机8 小时前
CockroachDB权威指南——开始使用
数据库·分布式·架构
宁zz8 小时前
乌班图安装jenkins
运维·jenkins
松果猿8 小时前
空间数据库学习(二)—— PostgreSQL数据库的备份转储和导入恢复
数据库
无名之逆8 小时前
Rust 开发提效神器:lombok-macros 宏库
服务器·开发语言·前端·数据库·后端·python·rust
s9123601018 小时前
rust 同时处理多个异步任务
java·数据库·rust
大丈夫立于天地间8 小时前
ISIS协议中的数据库同步
运维·网络·信息与通信
你觉得2058 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义下载方法
大数据·人工智能·python·gpt·学习·机器学习·aigc
数据智能老司机8 小时前
CockroachDB权威指南——CockroachDB 架构
数据库·分布式·架构
啊喜拔牙8 小时前
1. hadoop 集群的常用命令
java·大数据·开发语言·python·scala