详解Apache Kafka的数据模型

本文我们探讨Kafka的事件驱动架构的数据模型。

搭建环境

kafka集群有多个注册到Zookeeper集群的kafka代理组成。为了简化,我们直接使用Confluent发布的Docker 镜像和docker-compose文件。首先下载带三个节点kafka集群的docker-compose.yml文件:

$ BASE_URL="https://github.com/confluentinc/kafka-images/blob/master/examples/kafka-cluster"
$ curl -Os "$BASE_URL"/docker-compose.yml

现在启动容器及服务:

$ docker-compose up -d

最后我们验证kafka代理是否已启动:

kafka-3_1      | [2022-10-02 11:57:02,691] INFO [KafkaServer id=3] started (kafka.server.KafkaServer)
kafka-1_1      | [2022-10-02 11:56:54,949] INFO [KafkaServer id=1] started (kafka.server.KafkaServer)
kafka-2_1      | [2022-10-02 11:57:02,683] INFO [KafkaServer id=2] started (kafka.server.KafkaServer)

事件概述

在介绍事件驱动系统的数据建模之前,我们需要了解一些概念,例如事件、事件流、生产者-消费者和主题。

事件

事件在kafka中表示现实世界发生某事情的日志信息。通过键值对消息及一些属性(如时间戳、元数据、消息头等)记录信息。
假设象棋游戏,对于移动事件表示为:

{player1:Rook, a1->a5} @ 2022/10/02 00:12:30 

我们看到事件包括参与者的键信息,以及动作和发生时间。这里player1表示参与者,动作表示在2022/10/02 00:12:30 时间车从a1移动到a5。

消息流

kafka是捕获事件作为事件流的事件流处理系统。在象棋游戏中,事件流记录玩家的一些列棋子移动。每个事件发生时,棋盘的快照表示状态,通常使用传统的表模式存储对象的最新静态状态。

另一方面,事件流能帮助我们捕获两个连续状态的动态变化。如果播放一系列这样的不可变事件,就可以从一个状态过渡到另一个状态。这就是事件流和传统表之间的关系,通常称为流表二元性。

要是在棋盘上移动两步产生两个连续事件:

{player1:Rook, a1->a5} @ 2022/10/02 00:12:30 
{player1:Rook, a5->e5} @ 2022/10/02 00:12:32 

主题

本节我们学习kafka如何对消息进行分类:

分类

kafka消息中,产生事件方通常称为生产者,读取并消费消息者称为消费者。

现实场景中,每个生产者产生不同类型的消息,如果消费者过滤相关消息、忽略其他消息会造成极大的资源负担。为了避免这个问题,Kafka使用主题对消息进行分组,这样消费者仅消费特定分组的事件效率更高。

在上面象棋示例中,可以创建chess-moves主题接收所有移动事件:

$ docker run \
  --net=host --rm confluentinc/cp-kafka \
  kafka-topics --create --topic chess-moves \
  --if-not-exists \
  --partitions 1 --replication-factor 1 \
  --bootstrap-server localhost:22181
Created topic "chess-moves".

生产者和消费者

现在看生产者和消费如何处理kafka主题消息。使用kafka提供的 kafka-console-producer 和 kafka-console-consumer 工具进行演示。

首先启动kafka-producer容器并在其中执行生产者程序:

$ docker run \
--net=host \
--name=kafka-producer \
-it --rm \
confluentinc/cp-kafka /bin/bash
# kafka-console-producer --broker-list localhost:19092,localhost:29092,localhost:39092 \
--topic chess-moves \
--property parse.key=true --property key.separator=:

同时启动另一个kafka-consumer消费者容器并执行消费者程序:

$ docker run \
--net=host \
--name=kafka-consumer \
-it --rm \
confluentinc/cp-kafka /bin/bash
# kafka-console-consumer --bootstrap-server localhost:19092,localhost:29092,localhost:39092 \
--topic chess-moves --from-beginning \
--property print.key=true --property print.value=true --property key.separator=:

现在通过生产者发送消息:

>{Player1 : Rook, a1->a5}

以为消费者是活动的,因此会消费到Player1的消息:

{Player1 : Rook, a1->a5}

分区

接下来讨论kafka通过分区进一步对消息进行分组,以提升整个系统的性能。

并发性

我们可以把主题分为多个分区,让多个消费者消从不同的分区消费消息。通过这种并发方式,能够提升整个系统性能。

kafka创建主题时使用服务器级选项,缺省为1。但创建主题时可以显示制定分区数,对于已存在的主题,可以更改其分区数。下面对上面创建主题更改其分区数为3:

$ docker run \
--net=host \
--rm confluentinc/cp-kafka \
bash -c "kafka-topics --alter --bootstrap-server localhost:32181 --topic chess-moves --partitions 3"
WARNING: If partitions are increased for a topic that has a key, the partition logic or ordering of the messages will be affected
Adding partitions succeeded!

分区键

在主题内部,kafka使用分区键跨多个分区处理消息。在生产端,生产者隐式地使用它将消息路由到其中一个分区。在消费端,每个使用者可以从特定的分区读取消息。标识分区是基于消息键计算得到的。

下面通过kafka-console-producer 工具创建新的新的消息,但这次记录两个玩家的移动事件:

# kafka-console-producer --broker-list localhost:19092,localhost:29092,localhost:39092 \
--topic chess-moves \
--property parse.key=true --property key.separator=:
>{Player1: Rook, a1 -> a5}
>{Player2: Bishop, g3 -> h4}
>{Player1: Rook, a5 -> e5}
>{Player2: Bishop, h4 -> g3}

现在有两个消费者,一个读取partition-1分区,另一个读取partition-2分区:

# kafka-console-consumer --bootstrap-server localhost:19092,localhost:29092,localhost:39092 \
--topic chess-moves --from-beginning \
--property print.key=true --property print.value=true \
--property key.separator=: \
--partition 1
{Player2: Bishop, g3 -> h4}
{Player2: Bishop, h4 -> g3}

我们可以看到Player2的所有移动都被记录到分区1中。以同样的方式,我们可以检查Player1的移动是否被记录到分区0中。

可伸缩性

如何区分主题和分区对于水平扩展至关重要。主题更像是预定义的数据分类,而分区是动态数据分类。

此外,一个主题中可以配置多少分区也是有实际限制的。这是因为每个分区都映射为代理节点文件系统中的一个目录。当我们增加分区的数量时,我们也增加了操作系统上打开的文件句柄的数量。

因此Confluent专家建议将每个代理的分区数量限制为100 x b x r,其中b是Kafka集群中的代理数量,r是复制因子。

总结

本文我们使用Docker环境来介绍Apache Kafka消息处理系统的数据建模。首先介绍事件、主题和分区的基础概念,然后通过生产、消费事件理解事件流的体系结构。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值