Kafka设计原理总结
1.Kafka介绍
(1)基本概念
-
活动数据:网站用户行为数据,例如PV(页面浏览量),UV(用户访问量)
-
运营数据: 监控系统性能指标(cpu利用率、负载,内存使用率,磁盘利用率,IO性能)
-
海量数据不可变
-
实时处理
(2)常用应用场景
-
解耦: 消息队列在处理过程中间插入了一个隐含的、基于数据的接口层,两边的处理过程都要实现这一接口。可独立扩展两端处理过程,只需要它门遵守同样接口约束。将Kafka作为整个系统的中枢,负责在任意两个系统之间传递数据。
-
可恢复性:即使一个处理消息的进程挂掉, 加入队列中的消息可以在系统恢复后被处理。
-
冗余: 如果数据处理失败,除非数据被持久化,否则将造成丢失。消息队列把数据进行持久化直到它们已经被完全处理,这样规避了数据丢失风险。许多消息队列所采用的"插入-获取-删除"范式中, 在把一个消息从队列中删除之前,需要系统明确指出该消息已经被处理完毕,从而确保数据被保存直到使用完毕。
-
缓冲:有助于控制和优化数据流传输速度,解决生产和消费消息速度不一致( 一般生产者速度大于消费者)。
-
扩展性:因为消息队列解耦了处理过程,所以增大消息入队和处理的频率是很容易的,只要另外增加处理过程即可。不需要改变代码、不需要调节参数。扩展就像调大电力按钮一样简单。
-
灵活性 & 峰值处理能力: 浏览突发场景并不常见,但如果时刻处理峰值比较浪费资源。使用消息队列能够 使关键组件顶住突发的访问压力,而不会因为突发的超负荷的请求而完全崩溃。
-
顺序保证:大部分消息队列本来就是排序的,Kafka能保证一个Partition内的消息的有序性。
-
异步通信:消息队列提供了异步处理机制, 允许用户把一个消息放入队列,但并不立即处理它,这样可以保留多条消息。
2.消息传送模式
(1) 点对点传送模式(Push)
-
消息持久在队列中,没有消费者时消息一直保留队列中
-
消息只能被消费一次,可保证消息有序处理,但一条消息只能被一个消费者使用。
-
消息代理将消息推送(Push)到消费者后,标记消息已被消费,但无法保证消费的处理语义。
-
Push 消息发送速率是由broker决定,目标是尽可能发布消息, 很容易造成consumer来不及处理消息。
(2) 发布订阅消息传递(Poll)
-
消息被持久在Topic中,当你发布一个消息,所有订阅这个topic的服务都能得到消息,即订阅者都能得到这个消息的拷贝。
-
消费者可订阅多个topic,同一条数据可被多个消费者消费,数据被消费后不会立马删除。
-
Kafka采用拉取模型(Poll),消费者控制消费速度,消费者可以按照任意偏移量进行消费。
-
当没有消息时,消费者采用轮询方式咨询是否有新消息。
3.结构基本概念
(1)Kafka集群概念
-
Kafka 把同一类数据进行汇总,每一类数据的集合就是一个Topic, 相当于表。
-
生产者Producer将同一类型的数据写入同一个Topic,消费者Consumer从同一个Topic中消费该同类数据。
-
Topic逻辑上的概念,因为实际存放在Topic的数据存放在 一个或多个partition,而 文件夹会以主题名+分区名r命名。
-
Topic有多个分区,相当于数据分成多份,存放在不同分区中。
-
分区是 物理概念,每个分区对应一个文件夹,存储分区的数据和索引文件。
-
一个topic 可以分布到多个 broker上, 一个 topic 可以分为多个partition,每个partition是一个有序的队列;分区是有序、不可修改的消息队列, 每个分区内消息是有序的。 仅保证同一分区内消息有序存储,不保证Topic整体(多个分区之间)有序
-
CG消费者组是为了加快消费的读取速度的一个模型, 一个消费者组中的多个消费者可以并行消费同一个Topic中的数据。
-
多个CG可以消费同一个Topic,这些消费者组之间是平等的, 即同一条消息可同时被多个消费者组消费。
-
同一个CG消费者组中的多个Consumer消费者之间是竞争关系,也就是说 同一条消息在一个消费者组中只能被一个消费者所消费。
-
Zookeeper负责保存Kafka的元数据
-
负责Kafka的集群管理,包括配置管理、动态扩展、Broker负载均衡、Leader选举、以及CG变化时重新平衡
(2)传输单位
-
CRC32: CRC32校验和,4个字节。
-
magic: Kafka服务程序协议版本号 ,用于做兼容。1个字节。
-
attributes: 该字段占1字节,其中低两位用来表示压缩方式,第三位表示时间戳类型(0表示LogCreateTime,1表示LogAppendTime),高四位为预留位置,暂无实际意义。
-
timestamp: 消息时间戳,当magic>0 时消息头必须包含该字段。8个字节。
-
key-length: 消息key长度,4个字节。
-
key: 消息key实际数据。
-
payload-length: 消息实际数据长度,4个字节。
-
payload: 消息实际数据 在实际存储一条消息还包括12字节的额外开销(LogOverhead):
-
消息的偏移量: 8字节,类似于消息的Id。
-
消息的总长度: 4字节
-
4.存储结构和原理
(1)整体架构
一些Producer向Kafka集群发布消息,之后由多个Consumer从Kafka集群中消费消息,Zookeeper为Kafka集群提供了相应的协调服务。
(2)整体存储层级结构
(3)Partition(分区)
文件夹的命名规则为:topic 名称+分区序号。例如,first主题有三个分区,则其对应的文件夹为 first-0,first-1,first-2。
(4)Segment(段文件,最小存储单元)
①设计原因
由于生产者生产的消息会不断追加到 log 文件末尾,为防止 log 文件过大导致数据定位效率低下,Kafka 采取了 分片 和 索引 机制,将每个 partition 分为多个 segment。
②物理结构
-
Segment文件时Kafka中的最小存储单元
-
每个 segment对应两种文件:index索引文件和log数据文件。
-
索引定位:以二分法查找对应的数据。
(5)Offset(偏移量)
偏移量是定位消息在分区队列中位置的分区编号。也是消息在分区队列中的唯一标识,它是由Zookeeper来负责维护的。
5.索引机制
(1)索引设计
-
提高消息写入和查询速度
-
为每个partition创建索引,索引文件存储在partition文件夹下
(2)两类稀疏索引
①偏移量索引
-
它是由Offset偏移量作为文件名称,以.index作为后缀的一个文件。其文件内部的内容格式是offset,position的形式。该偏移量索引采用了稀疏存储的存储方式。
②时间戳索引
-
该文件是以.timestamp作为后缀的文件,内容格式是timestamp,offset的形式。该文件同样采用了稀疏存储的存储方式。
(3)索引过程
-
首先按照偏移量查询数据,会查找Kafka偏移量索引,缩小要查找数据的范围,然后在小范围中进行快速扫描,即可加快查询的速度。
-
时间戳索引也是一样,缩小要查找的范围,然后在小范围中进行查询。