【Kafka】常见简单八股总结
为什么使用消息队列?
解耦
:- 我以我的一段开发经验举例:
【Kafka】登录日志处理的三次阶梯式优化实践:从同步写入到Kafka多分区批处理
我做过一个登录日志逻辑
,就是在登录逻辑末尾,加一段写进数据库登录日志表的逻辑,那么,如果我们啥都不用,就单纯同步写入(就是在login函数返回之前加一段写入逻辑),那么会拖慢login的操作,在高并发时,影响系统性能。- 如果我们把写入逻辑异步实现,就可以形成,
先让用户感知到登录成功的效果,对登录日志的写入我们放到后台执行
,这样的解耦形式。 - 那就要用到消息队列了,这时,简单一点,我们可以利用go的channl,快速搭建一个简易的消息队列,但是你自己写的很多功能是比不上kafka好使的,所以用kafka作为消息队列,是更好的选择。
Kafka 是基于主题(Topic)进行
消息发布与订阅
的模型,实现生产者和消费者之间松散耦合
削峰填谷
- 应对突发流量(如秒杀活动)时,消息队列可暂存超出下游服务处理能力的请求,下游服务按自身节奏消费,避免因流量峰值直接压垮系统。
异步处理
- 将非核心流程(如通知推送、数据统计)从主流程中剥离,通过消息队列异步处理,减少主流程阻塞
容错与持久化
- 应对分布式系统中,某个上游节点/服务宕机时,下游服务来不及处理其最后发出的数据,导致数据丢失的情况。
- 如果有一个队列做缓冲,那么他宕机前的所有发出数据,都可以暂存在这个队列中,等候处理。
数据流处理与实时分析
(万流归中)- 将多个服务产生的数据汇聚,方便实时分析
广播与多订阅模式
- 一个生产者发布的消息需要被多个消费者处理,单纯的点对点模式无法满足,需要kafka的订阅发布模式
设置多个消费者组,每个消费者组中的一个消费者,可以分别处理一次消息
解耦、削峰填谷、异步处理、容错与持久化、数据流处理与实时分析、广播与多订阅模式
Kafka 架构原理
1. Broker
- Broker 是 Kafka 的服务器实例,负责接收、存储和传输消息。Kafka 集群由一个或多个 Broker 组成,通常每个 Broker 是一个独立的物理或虚拟服务器。
- 每个 Broker 都可以存储多个
Topic
的数据,并为这些数据提供读取服务。Kafka 的分布式特性允许将数据分布在不同的 Broker 上,以实现水平扩展。
2. Producer(生产者)
- Producer 是消息的发送者,负责将数据发布到 Kafka 中的
Topic
。 - Producer 可以指定消息发送到某个
Partition
,也可以通过轮询或基于特定规则(如基于键的哈希值)来选择 Partition。
3. Consumer(消费者)
- Consumer 是消息的读取者,负责从 Kafka 的
Topic
中订阅并读取消息。 - Consumer 组的概念允许多个 Consumer 实例组成一个组,来平衡消费不同
Partition
的消息。
4. Topic 和 Partition
- Topic 是 Kafka 中消息的分类单位,类似于数据库中的表。每个
Topic
可以有多个Partition
,而Partition
是 Kafka 的并行处理单位。 - 每个
Partition
是一个有序的、不可变的日志文件,每条消息在Partition
中都有一个唯一的偏移量(offset)。Partition
保证了顺序性,而不同Partition
之间可以并行处理。
5. Zookeeper / Raft(控制器)
- Kafka 使用 Zookeeper 来管理集群元数据、协调 Broker 和维护
Partition
的 Leader 选举过程。 - 新的 Kafka 版本可以使用 KRaft 协议来替代 Zookeeper,用于集群控制和选举 Leader。
关于Raft协议:
是一种针对主节点宕机时,从节点如何快速选举出新主节点
的分布式一致性协议。核心解决3个问题:
- 从节点如何快速感知主节点宕机?
- 主节点会定期广播心跳,从节点接收后重置自身内置计数器。
- 若计数器归零前未收到心跳,从节点即判定主节点宕机。
- 如何选举新主节点?
- 感知宕机的从节点切换为候选者,向所有节点广播
"请求投票"
。- 其他节点收到后进行投票,获得大多数节点支持的候选者成为新主节点。
- 为什么从节点计数器要设为随机值,而非统一短时间?
- 若计数器统一,所有从节点会同时感知宕机并争当候选者,导致投票分散,需多次重试,降低效率。
- 随机计数器可让部分节点更早发起选举,优先获得多数票,实现快速选主。
补充
- 任期(Term):每个选举周期的唯一标识(递增整数),确保每次选举在新任期内进行,避免旧投票干扰。
- 投票原则:
一任期内仅投一票
,且优先给日志更新的候选者投票(保证数据一致性)。
6. Leader 和 Follower
Kafka 通过 Partition 副本机制 来
保证数据的高可用性
。
副本机制:每个 partition 有多份
replica
,分为Leader 和 Follower
。
(且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器
,同一机器对同一个分区也只可能存放一个副本
(包括自己)。)
- 每个
Partition
都有一个 Leader,负责处理所有的读写请求。其他副本称为 Follower,它们从 Leader 同步数据。
围绕leader和follower,可以引出
三种ACK机制
,在配置partition时,分别决定了不同级别的消息可靠性
acks=0
:Producer 只管发 不管 Broker 是否收到 → 可能丢acks=1
:Producer 发消息,Leader 收到即确认收到 → Leader 崩了可能丢acks=all
:Producer 发消息,Leader 和 Follower 都收到消息,Leader 确认消息发送成功 → Broker 崩了可能丢
- 当 Leader 宕机时,Kafka 会自动从 Follower 中选举新的 Leader,以保证高可用性。
Kafka 的分区 Leader 选举机制不使用 Raft 协议,在kafka 2.8之前是依赖 ZooKeeper 进行协调,kafka 2.8之后
即 Kafka Raft 协议
Raft协议 适用于单个集群的一致性管理,而 KRaft 是针对 Kafka 分区副本的分布式场景优化,支持多分区并行选举
。
进一步梳理:
一、再次理解核心概念的正确关系
-
Topic(主题)
- Topic 是 Kafka 中消息的逻辑分类,类似于一个消息队列的名称。例如,电商系统中可能有“订单消息”“支付消息”等多个 Topic,分别存储不同类型的消息。
- Topic 本身并不直接存储消息,而是通过“分区(Partition)”来分布式存储消息。
-
Partition(分区)
- 每个 Topic 可以被划分为多个 Partition(数量可配置),消息会被分散存储在这些 Partition 中。
- Partition 是 Kafka 实现高吞吐量和分布式存储的核心:
- 多个 Partition 可以分布在不同的 Broker 上(一个 Broker 可以存放多个 Partition),实现负载均衡。
- 消息在 Partition 中是有序存储的(按写入顺序形成日志),但不同 Partition 之间的消息无序。
-
Broker(服务器节点)
- Broker 是 Kafka 集群中的单个服务器节点,负责存储消息、处理生产者和消费者的请求。
- 一个 Kafka 集群由多个 Broker 组成,Broker 之间通过 ZooKeeper 协调管理(如集群元数据、分区副本分配等)。
- Broker 存储的是 Partition,而不是直接存储 Topic:一个 Topic 的多个 Partition 可以分布在多个 Broker 上,单个 Broker 也可以存放多个不同 Topic 的 Partition。
二、生产者与消费者的工作流程
-
生产者(Producer)
- 生产者向指定的 Topic 发送消息,Kafka 会根据一定的规则(如哈希、轮询或自定义策略)将消息分配到该 Topic 的某个 Partition 中。
- 消息一旦写入 Partition,就会被持久化(默认存盘),并生成一个唯一的偏移量(Offset)标识其在 Partition 中的位置。
从这里可以引出kafka的
高效持久化
核心机制:
0. Kafka 的 Partition 本质上是一个日志文件
(Log),消息被写入时采用 “追加写入” 的方式(即只能在文件末尾顺序添加,不允许随机修改或删除)- kafka是存在磁盘的,向指定topic发消息,然后写入partition,(在磁盘上是
顺序写入
的,众所周知,在机械硬盘上,顺序写入速度可以媲美内存,固态更不用说了)将磁盘的性能发挥到了极致 - 由于消息只能追加在上一条消息末尾,为了适应磁盘顺序写入,引入偏移量机制,无需维护复杂的索引结构(仅通过 Offset 定位)减少了元数据开销,进一步提升了写入性能。
- 消费者通过记录 Offset,知道下次从哪个位置开始消费(例如,消费完 Offset=5 的消息后,下次从 Offset=6 开始)。
- 因此 Partition 内的消息通过 Offset
天然保持有序
(这也是 Kafka 能保证 “分区内消息有序”
的核心)。 - Offset 仅在单个 Partition 内有效,不同 Partition 的 Offset 相互独立
-
消费者(Consumer)与消费者组(Consumer Group)
- 消费者从 Topic 中读取消息,必须指定消费的 Partition(由 Kafka 自动分配或手动指定)。
- 消费者组是多个消费者的集合,同一个消费者组内的消费者共同消费一个 Topic 的所有 Partition,且一个 Partition 只能被同一个消费者组内的一个消费者消费(避免重复消费)。
- 不同消费者组可以独立消费同一个 Topic(彼此互不影响),例如“订单消息”Topic 可以被“物流系统”和“数据分析系统”两个消费者组分别消费。
三、总结关系图(简化)
Kafka 集群
├─ Broker 1
│ ├─ Topic A 的 Partition 0
│ └─ Topic B 的 Partition 1
├─ Broker 2
│ ├─ Topic A 的 Partition 1
│ └─ Topic C 的 Partition 0
└─ Broker 3└─ Topic B 的 Partition 0
- Topic A 包含 2 个 Partition,分别在 Broker 1 和 Broker 2 上。
- 每个 Broker 存放了不同 Topic 的 Partition。
kafka的存储机制
-
消息持久化
- Kafka 的存储机制主要围绕 存在磁盘上的日志(Log) 文件来实现数据的高效存储和读取。每个 Partition 被存储为一个 日志文件,
消息按照追加写
(顺序)的方式存储到日志中。
通过 offest 顺序
写入
,顺序读取
- Kafka 的存储机制主要围绕 存在磁盘上的日志(Log) 文件来实现数据的高效存储和读取。每个 Partition 被存储为一个 日志文件,
-
Segment分段存储
- 每个 Partition 日志文件会进一步被
分为多个 Segment
。Segment 是物理上日志文件的一部分
,当一个 Segment达到预定大小或时间限制
时,Kafka 会关闭这个 Segment 并开始写入下一个 Segment。
分段存储
的方式使得 Kafka 在删除旧消息时
不需要修改文件,只需要删除老的 Segment
文件即可 - 每个 Partition 日志文件会进一步被
-
消息保留策略
- 基于
时间保留
:可以配置 Kafka 将 Partition中,超过设定时间的Segment删除,例如保留 7 天的数据。 - 基于
大小保留
:可以根据每个 Partition 日志文件的大小来设置消息保留,超过设定大小后,删除最早的 Segment。
- 基于
-
日志压缩
- 永久保留最新版本的每个消息键。对于相同键的消息,Kafka 只保留最新的,删除旧的。
-
零拷贝
- Kafka 在内存和网络之间的传输
不经过 CPU 的数据拷贝
。减少了 CPU 和内存的开销,极大提高了数据传输效率
在生产者发送消息、Broker 转发消息以及消费者消费消息时都能发挥作用
- Kafka 在内存和网络之间的传输
Kafka的消费者策略
- 单独消费者模式
- 单个消费者独占订阅的Topic分区,其他消费者无法同时消费这些分区。
- 消费者组模式
- 多个消费者组成一个组,共同消费同一Topic,每个分区仅被组内一个消费者处理。
- 不同消费组可独立消费同一Topic,互不干扰。
- 通过动态增减消费者实例,
灵活扩展处理能力
,提升效率。
一、Kafka 确保一致性的核心机制
- 副本同步机制:每个分区的 Follower 副本实时从 Leader 副本同步数据,保证副本间数据一致。
- ISR 列表管理:仅维护与 Leader 数据同步的副本(In-Sync Replicas),非 ISR 副本不参与数据确认,避免数据不一致。
- Leader 唯一写入:所有读写操作由 Leader 副本处理,Follower 仅同步数据,确保同一分区的数据操作入口唯一。
- 选举规则约束:Leader 宕机时,仅从 ISR 中选举新 Leader,保证新 Leader 拥有最新数据,避免数据回退。
二、Kafka 确保可靠性的核心机制
- 持久化存储:消息按顺序写入磁盘并生成 Offset,即使 Broker 宕机,数据也不会丢失。
- 生产者确认机制:通过
acks
参数控制消息确认级别(如acks=-1
要求 ISR 中多数副本确认),确保消息被安全存储。 - 副本冗余:多副本机制实现数据冗余,单个副本故障时,其他副本可继续提供服务。
- 消费者 Offset 管理:消费者通过提交 Offset 记录消费进度,支持手动提交,避免重复消费或数据丢失。
- 故障自动恢复:Leader 故障后自动从 ISR 选举新 Leader,Broker 故障恢复后可重新加入集群同步数据。