Debezium发布历史38

原文地址: https://debezium.io/blog/2018/08/30/streaming-mysql-data-changes-into-kinesis/

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

将 MySQL 数据更改流式传输到 Amazon Kinesis
八月 30, 2018 作者: Gunnar Morling
讨论 实例
大多数时候 Debezium 用于将数据更改流式传输到Apache Kafka中。如果您使用其他流媒体平台(例如Apache Pulsar)或基于云的解决方案(例如Amazon Kinesis、Azure Event Hubs等)怎么办?您仍然可以受益于 Debezium 强大的变更数据捕获 (CDC) 功能并从 MySQL、Postgres、SQL Server 等数据库获取变更吗?

事实证明,只需一点粘合代码,您就可以!接下来,我们将讨论如何使用 Debezium 捕获 MySQL 数据库中的更改并将更改事件流式传输到 Kinesis(亚马逊云上提供的完全托管的数据流服务)。

Debezium 嵌入式引擎简介
Debezium 是作为 Kafka 的一组连接器实现的,因此通常通过Kafka Connect运行。但 Debezium 有一个小亮点尚未广为人知,那就是嵌入式引擎。

使用此引擎时,Debezium 连接器不会在 Kafka Connect 中执行,而是作为嵌入到您自己的 Java 应用程序中的库来执行。为此,debezium 嵌入式模块提供了一个小型运行时环境,用于执行原本由 Kafka Connect 框架处理的任务:从连接器请求更改记录、提交偏移量等。连接器生成的每个更改记录都会被传递到已配置的事件处理程序方法,在我们的示例中,该方法会将记录转换为其 JSON 表示形式,并使用 Kinesis Java API 将其提交到 Kinesis 流。

整体架构如下:
图片来自于官网
Debezium发布历史38_第1张图片

Debezium 嵌入式引擎流式传输至 Amazon Kinesis
现在让我们看一下所需代码的相关部分。完整的可执行示例可以在 GitHub 上的debezium-examples存储库中找到。

设置
为了使用 Debezium 的嵌入式引擎,请将debezium 嵌入式依赖项以及您选择的 Debezium 连接器添加到项目的pom.xml中。下面我们将使用 MySQL 连接器。我们还需要添加对Kinesis Client API 的依赖项,因此需要以下依赖项:



io.debezium
debezium-embedded
0.8.3.Final


io.debezium
debezium-connector-mysql
0.8.3.Final


com.amazonaws
amazon-kinesis-client
1.9.0


配置嵌入式引擎
Debezium 嵌入式引擎是通过io.debezium.config.Configuration. 此类可以从系统属性或给定的配置文件中获取值,但为了示例,我们将通过其流畅的构建器 API 简单地传递所有必需的值:

Configuration config = Configuration.create()
.with(EmbeddedEngine.CONNECTOR_CLASS, “io.debezium.connector.mysql.MySqlConnector”)
.with(EmbeddedEngine.ENGINE_NAME, “kinesis”)
.with(MySqlConnectorConfig.SERVER_NAME, “kinesis”)
.with(MySqlConnectorConfig.SERVER_ID, 8192)
.with(MySqlConnectorConfig.HOSTNAME, “localhost”)
.with(MySqlConnectorConfig.PORT, 3306)
.with(MySqlConnectorConfig.USER, “debezium”)
.with(MySqlConnectorConfig.PASSWORD, “dbz”)
.with(MySqlConnectorConfig.DATABASE_WHITELIST, “inventory”)
.with(MySqlConnectorConfig.TABLE_WHITELIST, “inventory.customers”)
.with(EmbeddedEngine.OFFSET_STORAGE,
“org.apache.kafka.connect.storage.MemoryOffsetBackingStore”)
.with(MySqlConnectorConfig.DATABASE_HISTORY,
MemoryDatabaseHistory.class.getName())
.with(“schemas.enable”, false)
.build();
如果您曾经在 Kafka Connect 中设置过 Debezium MySQL 连接器,那么您会觉得大多数属性都很熟悉。

但让我们更详细地讨论OFFSET_STORAGE和选项。DATABASE_HISTORY它们处理如何保存连接器偏移和数据库历史记录。通过 Kafka Connect 运行连接器时,两者通常都存储在特定的 Kafka 主题中。但这不是这里的选择,因此需要替代方案。对于这个例子,我们只是将偏移量和数据库历史记录保存在内存中。即,如果引擎重新启动,则该信息将丢失并且连接器将从头开始,例如使用新的初始快照。

OffsetBackingStore虽然超出了本文的范围,但分别创建和合约的替代实现并不会太困难DatabaseHistory。例如,如果您完全致力于 AWS 云服务,您可以考虑将偏移量和数据库历史记录存储在 DynamoDB NoSQL 存储中。请注意,与 Kafka 不同,Kinesis 流不适合存储数据库历史记录。原因是,Kinesis 数据流的最长保留期为 7 天,而数据库历史记录必须在连接器的整个生命周期内保留。另一种选择是分别使用基于现有文件系统的实现FileOffsetBackingStore和FileDatabaseHistory。

下一步是EmbeddedEngine根据配置构建实例。同样,这是使用流畅的 API 完成的:

EmbeddedEngine engine = EmbeddedEngine.create()
.using(config)
.using(this.getClass().getClassLoader())
.using(Clock.SYSTEM)
.notifying(this::sendRecord)
.build();
这里最有趣的部分是notifying调用。此处传递的方法将由引擎为每个发出的数据更改记录调用。那么我们来看看这个方法的实现。

将更改记录发送到 Kinesis
方法sendRecord()是奇迹发生的地方。我们将传入的内容转换SourceRecord为等效的 JSON 表示形式,并将其传播到 Kinesis 流。

为此,了解 Apache Kafka 和 Kinesis 之间的一些概念差异非常重要。具体来说,Kafka 中的消息有一个键和一个值(两者都是任意字节数组)。对于 Debezium,数据更改事件的键表示受影响记录的主键,值是由新旧行状态以及一些附加元数据组成的结构。

另一方面,在 Kinesis 中,消息包含数据 blob(同样是任意字节序列)和分区键。Kinesis 流可以分为多个分片,分区键用于确定给定消息应进入哪个分片。

现在,人们可以考虑将 Debezium 的更改数据事件中的键映射到 Kinesis 分区键,但分区键的长度限制为 256 字节。根据捕获表中主键列的长度,这可能还不够。因此,更安全的选择是根据更改消息键创建哈希值并将其用作分区键。这又意味着更改消息键结构应添加到 Kinesis 消息的数据 blob 的实际值旁边。虽然键列值本身也是值结构的一部分,但否则消费者将不知道哪些列构成主键。

考虑到这一点,让我们看一下实现sendRecord():

private void sendRecord(SourceRecord record) {
// We are interested only in data events not schema change events
if (record.topic().equals(“kinesis”)) {
return;
}

// create schema for container with key *and* value
Schema schema = SchemaBuilder.struct()
    .field("key", record.keySchema())
    .field("value", record.valueSchema())
    .build();

Struct message = new Struct(schema);
message.put("key", record.key());
message.put("value", record.value());

// create partition key by hashing the record's key
String partitionKey = String.valueOf(
    record.key() != null ? record.key().hashCode() : -1);

// create data blob representing the container by using Kafka Connect's
// JSON converter
final byte[] payload = valueConverter.fromConnectData(
    "dummy", schema, message);

// Assemble the put-record request ...
PutRecordRequest putRecord = new PutRecordRequest();

putRecord.setStreamName(record.topic());
putRecord.setPartitionKey(partitionKey);
putRecord.setData(ByteBuffer.wrap(payload));

// ... and execute it
kinesisClient.putRecord(putRecord);

}
代码非常简单;如上所述,它首先创建一个包含传入源记录的键和值的容器结构。然后使用 Kafka Connect( 的实例JsonConverter)提供的 JSON 转换器将该结构转换为二进制表示形式。然后,aPutRecordRequest由该 blob、分区键和更改记录的主题名称组合而成,最后发送到 Kinesis。

Kinesis 客户端对象可以重复使用并设置一次,如下所示:

// Uses the credentials from the local “default” AWS profile
AWSCredentialsProvider credentialsProvider =
new ProfileCredentialsProvider(“default”);

this.kinesisClient = AmazonKinesisClientBuilder.standard()
.withCredentials(credentialsProvider)
.withRegion(“eu-central-1”) // use your AWS region here
.build();
这样,我们就设置了 Debezium 的实例EmbeddedEngine,它运行配置的 MySQL 连接器并将每个发出的更改事件传递到 Amazon Kinesis。最后缺少的一步是实际运行引擎。这是使用一个单独的线程完成的Executor,例如:

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(engine);
请注意,您还应该确保最终正确关闭发动机。debezium-examples存储库中的随附示例显示了如何完成此操作。

运行示例
最后,让我们看一下运行完整的示例并使用 Kinesis 流中的 Debezium CDC 事件。首先克隆示例存储库并转到kinesis目录:

git clone https://github.com/debezium/debezium-examples.git
cd debezium-examples/kinesis
确保您已满足示例README.md中描述的先决条件;最值得注意的是,您应该安装本地 Docker,并且需要设置 AWS 帐户并安装 AWS 客户端工具。请注意,在 AWS 注册时,Kinesis 不属于免费套餐的一部分,即在执行该示例时您将支付少量费用。完成后,不要忘记删除您设置的流,我们不会支付您的 AWS 账单:)

现在运行 Debezium 的 MySQL 示例数据库来使用一些数据:

docker run -it --rm --name mysql -p 3306:3306
-e MYSQL_ROOT_PASSWORD=debezium
-e MYSQL_USER=mysqluser
-e MYSQL_PASSWORD=mysqlpw
debezium/example-mysql:0.8
为表中的更改事件创建 Kinesis 流customers:

aws kinesis create-stream --stream-name kinesis.inventory.customers
–shard-count 1
执行运行 Debezium 嵌入式引擎的 Java 应用程序(如果需要,请先将pom.xmlkinesis.region中的属性值调整为您自己的区域):

mvn exec:java
这将启动引擎和 MySQL 连接器,它会拍摄捕获的数据库的初始快照。

为了查看 Kinesis 流中的 CDC 事件,可以使用 AWS CLI(通常,您需要实现 Kinesis Streams 应用程序来使用事件)。为此,首先设置一个分片迭代器:

ITERATOR=$(aws kinesis get-shard-iterator --stream-name kinesis.inventory.customers --shard-id 0 --shard-iterator-type TRIM_HORIZON | jq ‘.ShardIterator’)
请注意如何使用jq实用程序从 Kinesis API 返回的 JSON 结构中获取迭代器的生成 id。接下来该迭代器可用于检查流:

aws kinesis get-records --shard-iterator $ITERATOR
您应该收到如下记录数组:

{
“Records”: [
{
“SequenceNumber”:
“49587760482547027816046765529422807492446419903410339842”,
“ApproximateArrivalTimestamp”: 1535551896.475,
“Data”: “eyJiZWZvcm…4OTI3MzN9”,
“PartitionKey”: “eyJpZCI6MTAwMX0=”
},

]
}
该Data元素是消息数据 blob 的 Base64 编码表示形式。jq再次派上用场:我们可以使用它来提取Data每个记录的部分并解码 Base64 表示(确保使用 jq 1.6 或更高版本):

aws kinesis get-records --shard-iterator $ITERATOR |
jq -r ‘.Records[].Data | @base64d’ | jq .
现在您应该看到 JSON 格式的更改事件,每个事件都有键和值:

{
“key”: {
“id”: 1001
},
“value”: {
“before”: null,
“after”: {
“id”: 1001,
“first_name”: “Sally”,
“last_name”: “Thomas”,
“email”: “[email protected]
},
“source”: {
“version”: “0.8.1.Final”,
“name”: “kinesis”,
“server_id”: 0,
“ts_sec”: 0,
“gtid”: null,
“file”: “mysql-bin.000003”,
“pos”: 154,
“row”: 0,
“snapshot”: true,
“thread”: null,
“db”: “inventory”,
“table”: “customers”,
“query”: null
},
“op”: “c”,
“ts_ms”: 1535555325628
}
}

接下来我们尝试更新 MySQL 中的一条记录:

Start MySQL CLI client

docker run -it --rm --name mysqlterm --link mysql --rm mysql:5.7
sh -c ‘exec mysql -h"KaTeX parse error: Undefined control sequence: \ at position 27: …3306_TCP_ADDR" \̲ ̲ -P"MYSQL_PORT_3306_TCP_PORT" -uroot -p"$MYSQL_ENV_MYSQL_ROOT_PASSWORD"’

In the MySQL client

use inventory;
update customers set first_name = ‘Trudy’ where id = 1001;
如果您现在再次获取迭代器,您应该会看到另一个代表该更新的数据更改事件:

{
“key”: {
“id”: 1001
},
“value”: {
“before”: {
“id”: 1001,
“first_name”: “Sally”,
“last_name”: “Thomas”,
“email”: “[email protected]
},
“after”: {
“id”: 1001,
“first_name”: “Trudy”,
“last_name”: “Thomas”,
“email”: “[email protected]
},
“source”: {
“version”: “0.8.1.Final”,
“name”: “kinesis”,
“server_id”: 223344,
“ts_sec”: 1535627629,
“gtid”: null,
“file”: “mysql-bin.000003”,
“pos”: 364,
“row”: 0,
“snapshot”: false,
“thread”: 10,
“db”: “inventory”,
“table”: “customers”,
“query”: null
},
“op”: “u”,
“ts_ms”: 1535627622546
}
}
完成后,按 Ctrl + C 停止嵌入式引擎应用程序,通过运行停止 MySQL 服务器docker stop mysql并删除Kinesis 中的kinesis.inventory.customers流。

总结与展望
在这篇博文中,我们演示了 Debezium 不仅可以用于将数据更改流式传输到 Apache Kafka,还可以用于将数据更改流式传输到 Amazon Kinesis 等其他流式平台。利用其嵌入式引擎并通过实现一些粘合代码,您可以受益于Debezium 提供的所有 CDC 连接器及其功能,并将它们连接到您选择的流解决方案。

我们正在考虑进一步简化 Debezium 的使用。我们不要求您实现自己的应用程序来调用嵌入式引擎 API,而是考虑提供一个小型的独立 Debezium 运行时,您可以简单地执行它。它将配置源连接器来运行和使用出站插件 SPI,并为 Kinesis、Apache Pulsar 等提供现成的实现。当然,这样的运行时还将提供合适的实现来安全地持久保存偏移量和数据库历史记录,并且它会提供监控、运行状况检查等手段。这意味着您可以以稳健可靠的方式将 Debezium 源连接器与您首选的流媒体平台连接起来,无需任何手动编码!

如果您喜欢这个想法,请查看 JIRA 问题DBZ-651并让我们了解您的想法,例如,在下面的评论部分或我们的邮件列表中留下对该问题的评论。

你可能感兴趣的:(debezium,CDC,FlinkCDC,运维,数据库,大数据)