Debezium发布历史20

原文地址: https://debezium.io/blog/2017/09/25/streaming-to-another-database/

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

将数据流式传输到下游数据库

九月 25, 2017 作者: Jiri Pechanec

mysql postgres smt 示例

在这篇博文中,我们将创建一个简单的流数据管道来持续捕获 MySQL 数据库中的更改,并将它们近乎实时地复制到 PostgreSQL 数据库中。我们将展示如何在不编写任何代码的情况下完成此操作,而是通过使用和配置 Kafka Connect、Debezium MySQL 源连接器、Confluence JDBC 接收器连接器和一些单消息转换 (SMT)。

这种通过 Kafka 复制数据的方法本身确实非常有用,但当我们可以将近乎实时的数据更改流与其他流、连接器和流处理应用程序相结合时,它会变得更加有利。最近的Confluence 博客文章系列展示了类似的流数据管道,但使用不同的连接器和 SMT。Kafka Connect 的优点在于您可以混合和匹配连接器以在多个系统之间移动数据。

我们还将演示Debezium 0.6.0中发布的一项新功能: CDC 事件扁平化的单个消息转换。

拓扑结构

该场景的一般拓扑如下图所示:

图片来源于debezium官网

图 1:一般拓扑

为了稍微简化设置,我们将仅使用一个包含所有连接器的 Kafka Connect 实例。即该实例将充当事件生产者和事件消费者:

图片来源于debezium官网

图 2:简化的拓扑

配置

我们将使用此组合来快速部署演示。该部署由以下 Docker 映像组成:

阿帕奇动物园管理员

阿帕奇·卡夫卡

经过更改的丰富的Kafka Connect / Debezium镜像

PostgreSQL JDBC 驱动程序放入/kafka/libs目录中

Kafka Connect JDBC Connector(由Confluence开发)放入/kafka/connect/kafka-connect-jdbc目录

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

空 PostgreSQL

Debezium MySQL 连接器旨在专门捕获数据库更改,并提供有关这些事件的尽可能多的信息,而不仅仅是每行的新状态。同时,Confluence JDBC Sink Connector 的设计目的是根据消息的结构将每条消息简单地转换为数据库插入/更新插入。因此,两个连接器具有不同的消息结构,但它们也使用不同的主题命名约定和表示已删除记录的行为。

当使用并非设计用于协同工作的连接器时,结构和行为上的不匹配很常见。但这是我们可以轻松处理的事情,我们将在接下来的几节中讨论如何处理。

活动形式

Debezium 以复杂的格式发出事件,其中包含有关捕获的数据更改的所有信息:操作类型、源元数据、连接器处理事件的时间戳以及更改前后的行状态。Debezium 将此结构称为"信封":

{

"op": "u",

"source": {

...

},

"ts_ms" : "...",

"before" : {

"field1" : "oldvalue1",

"field2" : "oldvalue2"

},

"after" : {

"field1" : "newvalue1",

"field2" : "newvalue2"

}

}

许多其他 Kafka Connect 源连接器没有能力了解这么多有关更改的信息,而是使用更简单的模型,其中每条消息直接代表行的后状态。这也是许多接收器连接器所期望的,Confluence JDBC Sink Connector 也不例外:

{

"field1" : "newvalue1",

"field2" : "newvalue2"

}

虽然我们认为 Debezium CDC 连接器提供尽可能多的细节实际上是一件很棒的事情,但我们还使您可以轻松地将 Debezium 的"信封"格式转换为许多其他连接器所期望的"行"格式。Debezium 以单一消息转换的形式提供了这两种格式之间的桥梁。该ExtractNewRecordState转换会自动提取新的行记录,从而有效地将复杂的记录扁平化为可由其他连接器使用的简单记录。

您可以在源连接器上使用此 SMT 在将消息写入 Kafka之前转换消息,也可以将源连接器更丰富的消息"信封"形式存储在 Kafka 中,并在接收器连接器上使用此 SMT 来转换消息从 Kafka 读取数据之后以及传递到接收器连接器之前。这两个选项都有效,这仅取决于您是否发现消息的信封形式可用于其他目的。

在我们的示例中,我们使用以下配置属性在接收器连接器上应用 SMT:

"transforms": "unwrap",

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

删除记录

当 Debezium 连接器检测到行被删除时,它会创建两个事件消息:删除事件和逻辑删除消息。删除消息有一个信封,其中字段中包含已删除行的状态before,并且after字段为null。逻辑删除消息包含与删除消息相同的键,但整个消息值为null,Kafka 的日志压缩利用这一点来知道它可以删除任何具有相同键的较早消息。许多接收器连接器(包括 Confluence 的 JDBC 接收器连接器)并不期望这些消息,如果它们看到任何一种消息,就会失败。默认情况下, SMTExtractNewRecordState将过滤掉这两者删除和逻辑删除记录,但如果您使用 SMT 并希望保留其中一种或两种消息,则可以更改此设置。

主题命名

最后但并非最不重要的一点是,主题的命名有所不同。Debezium 对代表其管理的每个表的目标主题使用完全限定的命名。命名遵循模式..。Kafka Connect JDBC 连接器使用简单的名称。

在更复杂的场景中,用户可以部署Kafka Streams框架来在源路由和目标路由之间建立详细的路由。在我们的示例中,我们将使用库存RegexRouterSMT,它将 Debezium 创建的记录路由到根据 JDBC 连接器架构命名的主题中。同样,我们可以在源连接器或接收器连接器中使用此 SMT,但在本示例中,我们将在源连接器中使用它,以便我们可以选择将在其中写入记录的 Kafka 主题的名称。

"transforms": "route",

"transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter",

"transforms.route.regex": "([^.]+)\.([^.]+)\.([^.]+)",

"transforms.route.replacement": "$3"

例子

踢轮胎,让我们试试我们的例子!

首先我们需要部署所有组件。

export DEBEZIUM_VERSION=0.6

docker-compose up

当所有组件启动后,我们将注册 JDBC Sink 连接器写入 PostgreSQL 数据库:

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

使用此注册请求:

{

"name": "jdbc-sink",

"config": {

"connector.class": "io.confluent.connect.jdbc.JdbcSinkConnector",

"tasks.max": "1",

"topics": "customers",

"connection.url": "jdbc:postgresql://postgres:5432/inventory?user=postgresuser&password=postgrespw",

"transforms": "unwrap", (1)

"transforms.unwrap.type": "io.debezium.transforms.ExtractNewRecordState",(1)

"auto.create": "true", (2)

"insert.mode": "upsert", (3)

"pk.fields": "id", (4)

"pk.mode": "record_value" (4)

}

}

该请求配置这些选项:

将 Debezium 的复杂格式分解为简单格式

自动创建目标表

如果不存在则插入一行或更新现有行

识别存储在Kafka记录值字段中的主键

然后必须设置源连接器:

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

使用此注册请求:

{

"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": "184054",

"database.server.name": "dbserver1", (1)

"database.whitelist": "inventory", (2)

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

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

"transforms": "route", (3)

"transforms.route.type": "org.apache.kafka.connect.transforms.RegexRouter", (3)

"transforms.route.regex": "([^.]+)\.([^.]+)\.([^.]+)", (3)

"transforms.route.replacement": "$3" (3)

}

}

该请求配置这些选项:

数据库的逻辑名称

我们要监控的数据库

一个SMT,定义与主题名称匹配的正则表达式..,并提取其中的第三部分作为最终的主题名称

让我们检查一下数据库是否同步。表的所​​有行都customers应该在源数据库(MySQL)和目标数据库(Postgres)中找到:

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 -e "select * from customers"'

±-----±-----------±----------±----------------------+

| id | first_name | last_name | email |

±-----±-----------±----------±----------------------+

| 1001 | Sally | Thomas | sally.thomas@acme.com |

| 1002 | George | Bailey | gbailey@foobar.com |

| 1003 | Edward | Walker | ed@walker.com |

| 1004 | Anne | Kretchmar | annek@noanswer.org |

±-----±-----------±----------±----------------------+

docker-compose exec postgres bash -c 'psql -U $POSTGRES_USER $POSTGRES_DB -c "select * from customers"'

last_name | id | first_name | email

-----------±-----±-----------±----------------------

Thomas | 1001 | Sally | sally.thomas@acme.com

Bailey | 1002 | George | gbailey@foobar.com

Walker | 1003 | Edward | ed@walker.com

Kretchmar | 1004 | Anne | annek@noanswer.org

在连接器仍在运行的情况下,我们可以向 MySQL 数据库添加一个新行,然后检查它是否已复制到 PostgreSQL 数据库中:

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 customers values(default, 'John', 'Doe', 'john.doe@example.com');

Query OK, 1 row affected (0.02 sec)

docker-compose exec -postgres bash -c 'psql -U $POSTGRES_USER $POSTGRES_DB -c "select * from customers"'

last_name | id | first_name | email

-----------±-----±-----------±----------------------

...

Doe | 1005 | John | john.doe@example.com

(5 rows)

概括

我们建立了一个简单的流数据管道,以近乎实时的方式将数据从 MySQL 数据库复制到 PostgreSQL 数据库。我们使用 Kafka Connect、Debezium MySQL 源连接器、Confluence JDBC 接收器连接器和一些 SMT 来完成此任务 - 所有这些都无需编写任何代码。由于它是一个流系统,它将继续捕获对 MySQL 数据库所做的所有更改并近乎实时地复制它们。

下一步是什么?

在未来的博客文章中,我们将使用 Elasticsearch 作为事件目标来重现相同的场景。

相关推荐
m0_5719575830 分钟前
Java | Leetcode Java题解之第543题二叉树的直径
java·leetcode·题解
2401_883041082 小时前
新锐品牌电商代运营公司都有哪些?
大数据·人工智能
青云交3 小时前
大数据新视界 -- 大数据大厂之 Impala 性能优化:融合机器学习的未来之路(上 (2-1))(11/30)
大数据·计算资源·应用案例·数据交互·impala 性能优化·机器学习融合·行业拓展
魔道不误砍柴功3 小时前
Java 中如何巧妙应用 Function 让方法复用性更强
java·开发语言·python
NiNg_1_2343 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
闲晨3 小时前
C++ 继承:代码传承的魔法棒,开启奇幻编程之旅
java·c语言·开发语言·c++·经验分享
_.Switch3 小时前
高级Python自动化运维:容器安全与网络策略的深度解析
运维·网络·python·安全·自动化·devops
2401_850410833 小时前
文件系统和日志管理
linux·运维·服务器
JokerSZ.3 小时前
【基于LSM的ELF文件安全模块设计】参考
运维·网络·安全
芯盾时代4 小时前
数字身份发展趋势前瞻:身份韧性与安全
运维·安全·网络安全·密码学·信息与通信