今天我们来聊一聊 Kafka 的架构。
大家一般熟悉的是三层结构:生产者、消费者、消息代理(Message Broker)。其实 Kafka 有更加详细的架构。
我们来一起看看。
Kafka 给自己的定位是事件流平台(event stream platform)。因此在消息队列中经常使用的 "消息"一词,在 Kafka 中被称为 "事件"。
下图详细展示了 Kafka 的架构和客户端 API 设计。我们可以看到,尽管生产者、消费者和消息代理仍然是架构的关键,但要构建一个高吞吐量、低时延的 Kafka,还需要更多的组件。让我们逐一介绍这些组件。
从高层次来看,架构分为两层:
计算层
存储层
计算层
计算层允许各种应用程序通过 API 与 Kafka Broker 通信。
生产者使用生产者 API。如果数据库等外部系统想与 Kafka 通信,它还提供 Kafka Connect 作为集成 API。
消费者通过消费者 API 与 Broker 通信。我们可以使用 Kafka Connect API 将事件数据路由到其他数据处理平台上,例如搜索引擎或数据库。
此外,消费者还可以使用 Kafka Streams API 进行流式处理。如果要处理无边界的数据流,我们可以创建一个 KStream。
下面的代码片段为主题 "订单 "创建了一个 KStream,并为 key 和 value 创建了 Serdes(Serializers and Deserializers,序列化和反序列化)。
如果我们只需要更新实体的最新状态,我们可以创建一个 KTable 来维护状态。
Kafka Streams 允许我们对事件流进行聚合、过滤、分组和连接。
final KStreamBuilder builder = new KStreamBuilder(); final KStreamorderEvents = builder.stream(Serdes.String(), orderEventSerde, "orders");
虽然 Kafka Streams API 在 Java 应用程序中运行良好,但有时我们可能希望部署一个独立的流处理模块,而不将其嵌入到应用程序中。这时,我们可以使用 ksqlDB。这是一个针对流处理进行了优化的数据库集群。它还提供了 REST API,供我们查询结果。
我们可以看到,有了计算层中的各种 API 支持,我们可以非常灵活地对事件流进行链式操作。
例如,我们可以在消费者中订阅主题 "orders",按照产品维度进行订单聚合,然后将每个产品的订单数发回 Kafka 主题 "ordersByProduct";另一个分析模块可以订阅这个主题并在界面上显示这些订单。
存储层
这一层由 Kafka Broker 组成。Kafka Broker 以集群模式运行。数据存储在不同主题的分区中。
主题就像一个数据库表,主题中的分区可以分布在不同的集群节点上。在分区内,事件严格按照偏移量(offset)排序。偏移量代表事件在分区中的位置,并单调递增。
在 Broker 上持久化的事件是不可变的(immutable)、只可追加的(append only),即使是删除也被模拟为删除事件,而不是直接从磁盘上删除数据。因此,生产者只能处理顺序写入,消费者只能顺序读取。
Kafka Broker 的职责包括管理分区、处理读写操作以及管理分区的数据复制。它的设计非常简单,因此易于扩展。
由于 Kafka Broker 是以集群模式部署的,因此有两个必要的组件来管理节点:控制面板和数据面板。
控制面板
控制平面管理 Kafka 集群的元数据。以前的版本中是由 Zookeeper 来管理控制器:挑选一个 Broker 作为控制器(Controller)。现在,Kafka 使用名为 KRaft 的共识模块来实现控制面板,选取几个 Broker 做为控制器。
为什么不再依赖 Zookeeper?因为使用 Zookeeper 时,我们需要维护两个不同类型的系统:一个是 Zookeeper,另一个是 Kafka。有了 KRaft,我们只需维护一种类型的系统,这使得配置和部署比以前容易得多。此外,KRaft 在向 Broker 传播元数据方面效率更高。
我们不会在这里讨论 KRaft 共识的细节。需要记住的一点是,控制器和 Broker 中的元数据缓存是通过 Kafka 中的一个特殊主题同步的。
数据面板
数据面板处理数据的复制操作。单个分区的数据可以在不同的 Broker 上有多份拷贝,这些拷贝之间需要进行数据同步。
下图是一个示例。主题 "订单"中的分区 0 在 3 个代理上有 3 个副本。Broker 1 上的分区是领导者(leader),当前数据偏移量为 4;Broker 2 和 3 上的分区是跟随者(follower),偏移量分别为 2 和 3。
第一步
为了赶上领导者,跟随者 1 发出偏移量为 2 的 FetchRequest,跟随者 2 发出偏移量为 3 的 FetchRequest。
第二步
然后,领导者相应地向两个跟随者发送数据。
第三步
由于跟随者的请求隐含地确认了先前获取记录的接收情况,因此领导者会将偏移量 2 之前的记录提交。
编辑:黄飞
全部0条评论
快来发表一下你的评论吧 !