一、什么是Kafka
Apache Kafka是一个分布式的基于发布订阅消息系统的消息队列,可以处理大量的数据,并使您能够将消息从一个端点传递到另一个端点
- Kafka适合离线和在线消息消费
- Kafka消息保留在磁盘上,并在群集内复制以防止数据丢失
- Kafka构建在ZooKeeper同步服务之上。 它与Apache Storm和Spark非常好地集成,用于实时流式数据分析
消息队列是一个用于接收消息、存储消息并且转发消息的中间件,主要是用于解决如下的场景:
- 异步:A服务做了一些事情,异步发送消息给服务B;
- 削峰/限流:有些服务(例如电商服务的秒杀),请求量很高,服务端处理不过来,那么请求先放到消息队列里面,然后服务端按照自己的能力来消费处理;
- 解耦:应用之间减少代码的耦合,使得应用的部署更加灵活;
二、基本架构介绍
- Producer :消息生产者,就是向 kafka broker 发消息的客户端
- Consumer :消息消费者,向 kafka broker 取消息的客户端
- Consumer Group (CG):消费者组,由多个 consumer 组成。消费者组内每个消费者负责消费不同分区的数据,一个分区只能由一个组内消费者消费;消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者【提高消费能力】
- Broker :一台 kafka 服务器就是一个 broker。一个集群由多个 broker 组成。一个 broker 可以容纳多个 topic
- Topic :消息主题分类,生产者和消费者面向的都是一个 topic,我们在收发消息时只需指定 topic。
- Partition: 分区。为了提升系统的吞吐,一个 topic 下通常有多个 partition,partition 分布在不同的 Broker 上,用于存储 topic 的消息,这使 Kafka 可以在多台机器上处理、存储消息,给 kafka 提供给了并行的消息处理能力和横向扩容能力。
- Replica: 副本,为保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 kafka 仍然能够继续工作,kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本, 一个 leader 和若干个 follower
- leader:每个分区多个副本的“主”,生产者发送数据的对象,以及消费者消费数据的对象都是 leader
- follower:每个分区多个副本中的“从”,实时从 leader 中同步数据,保持和 leader 数据 的同步。leader 发生故障时,某个 follower 会成为新的 follower
三、Kafka 架构深入
3.1 工作流程及文件存储机制
3.1 Kafka 生产者
数据可靠性保证
Kafka 高可靠性的核心是保证消息在传递过程中不丢失,涉及如下核心环节:
- 消息从生产者可靠地发送至 Broker;-- 网络、本地丢数据;
- 发送到 Broker 的消息可靠持久化;-- Pagecache 缓存落盘、单点崩溃、主从同步跨网络;
- 消费者从 Broker 消费到消息且最好只消费一次 -- 跨网络消息传输 。
ack 策略
针对问题 1,Kafka 为我们提供了三种 ack 策略,
- Request.required.acks = 0:请求发送即认为成功,不关心有没有写成功,常用于日志进行分析场景;
- Request.required.acks = 1:当 leader partition 写入成功以后,才算写入成功,有丢数据的可能;
- Request.required.acks= -1:ISR 列表里面的所有副本都写完以后,这条消息才算写入成功,强可靠性保证;
故障处理细节:Log 文件中的 HW 所有副本中最小的 LEO 和 LEO 每个副本的最后一个 offset,保证消费数据的完整性
消息发送策略
kafka 提供两类消息发送方式:同步(sync)发送和异步(async)发送,相关参数如下:
同步发送支持接受消息发送结果的回调
3.2 发送到 Broker 的消息可靠持久化
- Broker 异步刷盘机制
- Broker 接收到消息后只是将数据写入 PageCache 后便认为消息已写入成功,而 PageCache 中的数据通过 linux 的 flusher 程序进行异步刷盘(刷盘触发条:主动调用 sync 或 fsync 函数、可用内存低于阀值、dirty data 时间达到阀值),将数据顺序写到磁盘。
- Replica 副本机制
- 每组分区通常有多个副本,同组分区的不同副本分布在不同的 Broker 上,保存相同的消息(可能有滞后)
3.3 Kafka 消费者
一、消费方式:consumer 采用 pull(拉)模式从 broker 中读取数据
二、分区分配策略
一个 consumer group 中有多个 consumer,一个 topic 有多个 partition,确定那个 partition 由哪个 consumer 来消费
三、offset 维护
consumer 需要实时记录自己消费到了哪个 offset
offset 是消息在分区中的唯一标识,是一个单调递增且不变的值。Kafka 通过它来保证消息在分区内的顺序性,不过 offset 并不跨越分区,也就是说,Kafka 保证的是分区有序而不是主题有序。
四:可靠消费:
Consumer 在消费消息的过程中需要向 Kafka 汇报自己的位移数据,只有当 Consumer 向 Kafka 汇报了消息位移,该条消息才会被 Broker 认为已经被消费。因此,Consumer 端消息的可靠性主要和 offset 提交方式有关,Kafka 消费端提供了两种消息提交方式:
通常是通过手动提交 幂等实现消息的可靠消费。
3.4 分区的原因 Partition
- 方便在集群中扩展, topic 分为多个 partition 传递到多个 kafka 主机实现消息发送,可以更好的实现负载均衡
- 提高并发,以 Partition 为单位读写
数据进行 Partition 分区的原则
- 指明 partition 的情况
- 没有指明 partition 值但有 key 的情况,将 key 的 hash 值与 topic 的 partition 数进行取余得到 partition 值
- 既没有 partition 值又没有 key 值的情况下:第一次调用时随机生成一个整数,之后每次调用自增,将这个值与 topic 可用的 partition 总数取余得到 partition 值, round-robin 轮询调度算法
文件存储
为防止 log 文件,Kafka 采取了分片和索引机制,将每个 partition 分为多个 segment。每个 segment 对应两个文件——“.index”文件和“.log”文件
segment:分段。宏观上看,一个 partition 对应一个日志(Log)。由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据检索效率低下,Kafka 采取了分段和索引机制,将每个 partition 分为多个 segment,同时也便于消息的维护和清理。每个 segment 包含一个.log 日志文件、两个索引(.index、timeindex)文件以及其他可能的文件,每个 Segment 的数据文件以该段中最小的 offset 为文件名,当查找 offset 的 Message 的时候,通过二分查找快找到 Message 所处于的 Segment 中。
四、参考链接
Kafka 高可靠高性能原理探究
一文理解 kafka 如何保证消息顺序性
由于Kafka的一个 Topic 可以分为了多个 Partition,Producer发送消息的时候,是分散在不同 Partition,会导致消息顺序顺序是乱的。
- 全局有序:需要1个Topic只能对应1个Partition(降低了吞吐量)
- 局部有序:发消息的时候指定 Partition Key,Kafka对其进行Hash计算,Partition Key 相同的消息会放在同一个Partition(降低了吞吐量)
Kafka 为什么如此之快
- 磁盘顺序读写
- pageCache 缓存技术(内存中)
- 零拷贝技术(零拷贝技术不是指不发生拷贝,而是在用户态没有进行拷贝)
- sendfile零拷贝技术在内核态将数据从PageCache拷贝到了Socket缓冲区,这样就大大减少了不同形态的切换以及拷贝
- kafka分区架构和批量操作
kafka 和 rabbitmq 的区别
参考链接
主要是设计理念和使用场景的不同:
Rabbitmq 比 kafka可靠,kafka更适合IO高吞吐的处理