了解了 Kafka 架构就掌握了 Kafka 最核心的知识,Kafka 作为业界最知名、最流行的消息系统和流式处理组件,在面试中和日常工作中经常会见到。那么今天,我们就来聊聊 Kafka 的架构演化与升级,并通过图解的方式让你一目了然。
1.Kafka 初印象
Kafka 最初由 LinkedIn 公司开发,后来成为了 Apache 软件基金会的一个开源项目。它的主要设计目标是提供一个高吞吐量、可持久化、分布式的消息系统。
2.Kafka 基础架构
Kafka 最简单的基础架构如下:
Kafka 主要是由以下 4 部分组成:
- Producer(生产者):消息发送方,生产者负责创建消息,然后将其投递到 Kafka(Broker)中。
- Consumer(消费者):接收消息方,消费者连接到 Kafka 上并接收消息,进而进行相应的业务逻辑处理。
- Broker(代理):一个 Broker 可以简单地看作一个独立的 Kafka 服务节点或 Kafka 服务实例。大多数情况下也可以将 Broker 看作一台 Kafka 服务器,前提是这台服务器上只部署了一个 Kafka 实例。一个或多个 Broker 组成了一个 Kafka 集群。一般而言,我们更习惯使用首字母小写的 broker 来表示服务代理节点。
- ZooKeeper:ZooKeeper 是 Kafka(集群)中使用的分布式协调服务,用于维护 Kafka(集群)的状态和元数据信息,例如主题和分区的分配信息、消费者组和消费者偏移量等信息。Kafka 2.8.0 之后,Kafka 引入了 KRaft(Kafka Raft)模式,它提供了一种新的内置的共识机制来替代对 Zookeeper 的依赖。此时,Kafka 可以脱离 Zookeeper 单独运行,但需要配置 KRaft 控制器才行,Kafka 默认服务还是要配合 Zookeeper 运行的。
3.不同的消息类型怎么办?
在上述最基础的 Kafka 架构中我们会发现一个问题,那就是如果是不同的消息类型要怎么办?例如以下情况:
此时,我们可以把不同类型的消息存放在一起,但这样就需要给消息添加 type 字段,以区分不同的消息。
但添加了 type 字段之后,后面的维护和扩展又不方便,而且 type 越多,代码中的判断代码就越复杂,想象一下:一个复杂项目的消息类型是有成千上万个分类的,那我们的判断代码也要写成千上万个 if-else 判断不可?这要怎么解决呢?
这时候,我们就需要一个“消息分类机制”,这个机制在 Kafka 里被称之为 Topic(主题),如下图所示:
引入了 Topic 之后,不同的消息就可以发送到不同的 Topic 了,不同业务的生产者和消费者就可以实现相互隔离、互不影响了。
Broker 和 Topic 的关系:一个 Broker 中可以包含多个 Topic。
4.如何保证高性能?
4.1 数据分片
想要提升 Kafka 性能就需要水平扩展 Broker 数量,如下图所示:
在 Kafka 中,Topic 是用 Partition(分区)存储的,所以它正确的交互流程如下所示:
这小节核心知识点:
- Partition(分区)就是真正存储数据的消息队列。
- 有了集群和多个 Partition 之后,Kafka 的数据就可以实现分片存储了,性能也得到很大的提升。什么是数据分片?数据分片存储是一种将大量数据分散存储在多个不同位置或设备上的技术。
在数据量庞大的情况下,为了提高数据的存储效率、访问性能和可扩展性,将数据分割成较小的片段,然后分别存储在不同的节点或存储设备中。
以下是一些数据分片存储的特点和优势:
- 提高性能:通过将数据分散存储,可以并行地处理数据请求,从而加快数据的读取和写入速度。例如,在一个分布式数据库中,不同的分片可以同时响应查询,减少了总体的响应时间。
- 增强可扩展性:当数据量不断增长时,可以方便地添加更多的分片来扩展存储容量,而无需对整个系统进行大规模的重构。
- 避免单点性能瓶颈:数据分片可以使数据的存储和访问负载更加均衡地分布在多个节点上,避免单个节点成为性能瓶颈。4.2 消费组如果没有消费组,那么一个 Topic 只能被一个消费者消费,性能会很低,如下图所示:
- 并发执行:将一个主题内的消息分给多个消费者并发处理,提升了消息消费的性能。
- 容错性好:如果组内的某个消费者发生故障,Kafka 能够自动地将该消费者负责的分区重新分配给其他健康的消费者,确保消息不会被遗漏。
- 支持多种消费模式:通过调整消费者组的配置,可以实现不同的消费模式,如发布订阅模式(一对多)和队列模式(一对一)。在发布订阅模式下,一个消息可以被多个消费者组同时消费,每个消费者组内的消费者则共享该消息;在队列模式下,一个消息只能被一个消费者组内的某个消费者消费。这种灵活性使得Kafka可以适应不同的业务需求和数据处理场景。
- 动态扩展:随着业务规模的扩大或缩小,可以动态地增加或减少消费者组的成员。新加入的消费者会自动从已有的副本中拉取数据并开始消费;而离开的消费者会自动感知并停止消费。这种动态的扩展性使得 Kafka 能够随着业务的发展而灵活地扩展处理能力。消费组和分区的关系:消费者(数量) <= 分区数。
5.如何保证高可用?
Partition 备份节点叫做 Follower 节点,负责数据读写的节点叫做 Leader 节点。
Kafka 分区类型有以下两种:
- Leader Partition:主节点,负责数据写入和读取。
- Follower Partition:副本节点,用于数据备份和主节点宕机之后的分区选举,保证了 Kafka 服务的高可用。小结Kafka 架构最终组成如下:
- 生产者(Producer):负责将消息发送到 Kafka 集群。
- 消费组(Consumer Group):用于实现对一个主题(Topic)中消息进行并发消费和负载均衡的机制。
- 消费者(Consumer):负责从 Kafka 集群中读取、消费消息。
- 代理(Broker):Kafka 服务器(Kafka 服务),负责存储和转发消息。
- 主题(Topic):消息的逻辑分类,生产者将消息发送到特定的主题,消费者从特定的主题订阅消息。
- 分区(Partition):主题可以被分为多个分区,每个分区是一个有序的、不可变的消息序列。分区可以分布在不同的 broker 上,实现水平扩展。分区分为 Leader 分区,和 Follower 分区。
- Zookeeper:用于管理 Broker 集群的元数据,如分区分配、领导者选举、消费者组和消费者偏移量等信息等。
本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。