文章目录
- 1、什么是消息队列?
- 2、基础架构
- 3、Kafka为什么快
- 4、零拷贝
- 5、Rebalance机制
- 6、kafka如何避免重复消费
- 7、避免消息丢失
- 8、Kafka怎么实现消息的顺序消费
- 9、什么是ISR
- 10、Kafka文件存储机制
1、什么是消息队列?
kafka是一个消息队列的中间件,那什么是消息队列?消息队列是应用间异步通信的中间件,它由三部分组成:
- 生产者:负责生产消息,将消息发送给broker,是全部消息的发起者。
- broker:是消息的服务端,负责消息的存储、投递等功能,是最核心的部分。
- 消费者:负责消息的消费,根据消息承载的信息处理对应逻辑。
它的应用场景有: - 消息的异步处理:比如用户注册发送验证码,服务端只需要把协商好的消息发送至消息队列,不需要等待消费者回应,让消费者在空闲时去消息队列读取消息进行消费即可。
- 应用解耦:可以将一些不同源的应用管理起来,应用只需要将消息发送给消息队列,其它应用即可进行消费,无需在意应用是用什么语言开发的、是怎么开发的,某个应用宕机了也不会阻碍阻碍的运行,在其重启时,继续发送或者消费消息队列中消息即可。
- 流量削峰:生产者短时间把大量的任务发送至消息队列,消费者根据其消费能力平稳的消费消息。能够防止消息过多导致消费者宕机。
2、基础架构
如图所示,Kafka是一个分布式消息队列,它的核心包括:
- Broker:kafka集群中的服务器节点,也就是一台服务器。
- Topic:主题,用于存储同一种消息类型,一个主题的消息分布式的存储在多个服务器上。
- Partition:分区,将Topic分区的存储在不同的Broker中,能提高处理消息的并发度。
- 生产者:生产者生产消息,将其负载均衡的放入对应Broker的Topic分区中。
- 消费者:消费者从Broker中消费消息,同一个分区只能被一个消费者消费。
- 为了保证高可用,每个Partition数据都有从节点保存数据,主节点挂了,从节点补上。
Kafka集群中的一些状态信息,例如节点的在线信息、主题分区的主从信息会存储在Zookeeper中(2.8版本以前,以后可以选择不用)。
3、Kafka为什么快
- 使用了零拷贝技术,减少了数据的拷贝和上下文环境的切换。
- 使用了多个服务器分区的存储了同一个Topic,提高了吞吐量。
- 磁盘顺序读写:磁盘中文件的顺序读写能让其速度接近内存的操作。
- 批量删除和复制数据:数据被消费者消费后,并不会马上删除,而是等达到一定量后统一批量删除。
- 使用页缓存:避免使用了JVM,不需要GC垃圾回收,节省了垃圾回收的开销。
4、零拷贝
- 传统拷贝技术:以主机读取数据并将其通过套接字发送给其它服务器为例。流程如下:
- 发起读操作请求,CPU收到请求后给DMA发起调度命令,由DMA将磁盘数据写入内存缓冲区(第一次拷贝)取完成后给CPU发送读取完成消息。
- CPU再将内存缓冲区数据写入到用户缓冲区(第二次拷贝)。
- 将用户态数据写入Socket缓存区(第三次拷贝)。
- 完成后,CPU调度DMA,让DMA将Socket缓存区数据写入网卡缓存区(第四次拷贝),发送数据。
DMA技术是在主板上安装了一个DMA芯片,用于IO设备和内核之间的数据传输,以降低CPU的压力。
- 零拷贝技术:零拷贝并不是指没有拷贝过程,而是指用户态上没有拷贝过程。它使用了sedfile()函数去实现的。流程如下:
- 发起sedfile()请求,首先会在PageCache查找数据,若存在则直接开始滴2步,不存在则使用DMA将数据从磁盘上拷贝至PageCache缓存区。
- 读取完成后,DMA给CPU发送信号,CPU将内存地址和页内偏移量传输给Socket。
- DMA将PageCache中的缓存数据写入网卡设备中。
- DMA发送写完信号给Socket,返回Seedfile()调用结束。
5、Rebalance机制
Rebalance是kafka中的负载均衡机制。用于控制消费者均衡的消费消息。当有新的消费者加入或退出、订阅的改变、broker宕机等原因,会触发再平衡机制。
6、kafka如何避免重复消费
Kafka在消费分区中的消息时,会维护offset(偏移量)值,去避免重复消费的问题。默认情况下,消息消费完成后,会在下一次消费时,自动提交offset值,去避免重复消费,但是如果在消费者消费的过程中,应用程序挂掉了,可能会导致offset值设置失败,导致消息被重复的消费。此外,kafka有个再平衡(rebalance)机制,如果消费者在默认的5分钟内不能处理完分区中消息时,会触发再平衡机制,导致offset自动提交失败,而新的消费端还是会从没有提交的offset位置开始消费,从而导致重复消费的问题。
- 解决办法:
- 提高消费端消费性能,从而避免触发rebalance机制。
- 将rebalance时间拉长一些。
- 减少一次性从broker中获取的消息条数。
- 把每个消息生成一个hash值,存储在redis中,消费时查询该消息是否已经被消费,该方法使用的是幂等性的思想实现的。
7、避免消息丢失
消息丢失包括:
- 生产者消息丢失:指生产者发送消息到Kafka的broker中,这期间因为网络问题或者broker故障发送失败,而因为这个过程是异步进行的,生产者并不知道该消息发送失败。所以生产端避免消息丢失的核心是让生产者即时知道该消息发送失败,然后重新发送,具体做法有两种,一种是在发送消息的函数中设置回调函数,当消息发送失败时,通过回调函数及时通知生产者或者直接进行重试;另一种是将异步改为同步。此外kafka的生产者本身也提供了重试参数叫retires,如果消息发送失败会自动重试。
- 消费者消息丢失:一般不会出现,除非消费者消费失败了,但提交了offset,这样将会导致消息丢失。可以通过重新设置offset去恢复数据。
- Kafka内部消息丢失:ack=0时,生产者会不等待broker的响应,就认为消息发送成功了,这样可能会导致消息丢失。ack=1时,broker中的leder会不管follow是否同步完成,就返回给生产者成功的响应,若这时leader挂了,可能会导致消息丢失。ack=-1,broker中的leder会等待ISR中的follow全部同步完成,再返回响应给生产者,这样将不会出现消息丢失。
8、Kafka怎么实现消息的顺序消费
在Kafka中,生产者生产的同一个Topic的消息,会根据key值分布式的存储在不同的服务器的分区中,消费者消费时,同一个Topic不同分区的消息可能被多个消费者消费,而使得消息的消费顺序和生产者生产的顺序不一致。解决办法是:
- 自定义路由算法,将消息放入同一个服务器的同一个分区中,让一个消费者去消费该分区的消息,以实现顺序消费。
9、什么是ISR
Kafka为了保证高可能,对于分区的数据存储采用了主从机制,其中主分区leader负责事务的处理,从分区follow负责同步主分区数据状态,当leader挂了后,从follow列表中挑选与主分区最一致作为新的leader。ISR主要就是为了解决怎么挑选新的leader而设计的,在ISR中记录了和leader保持一定程度同步的follow,从中就可以挑选最接近的follow作为新的leader。
AR:记录了分区中的所有副本,包括某个Partition所有的主分区,从分区。
OSR: 记录了滞后leader过多的follow,当其跟上leader的脚步和其保持同步了,将会移至ISR中。
10、Kafka文件存储机制
Kafka中的每个分区的数据将会被分为多个segement进行存储。每个segement文件中包含.index、.log、.timeindex文件,其中:
- .index:存储了每条数据对应在.log文件中的切片。例如偏移量为28的数据,对应的存储在.log文件的第[29,102]个字节。
- .log文件:真正存储数据的文件。
- .timeindex文件:记录了时间戳和对应的偏移量。用于根据时间戳快速的查找消息。