Kafka
Kafka
1. 什么是消息队列,有哪些使用场景
一发一存一消费
1.1 应用解耦
例如A系统将消息写入到队列,B系统订阅消息
1.2 流量削峰
例如5k个请求发送到MQ,MQ只保证向后端发送2k个请求
1.3 异步处理
例如将用户注册成功的消息发送到MQ,其他系统(发送邮件,发送短信)等订阅MQ消息,并行操作
1.4 RPC
2. 如何保证消息不丢失
2.1 生产者(发不丢)
配置ack=-1和retry,如果重试几次后仍有异常则记录补偿
ack:
1: 只要分区的leader写入成功就是成功0: 发送消息之后不需要等待任何回应(可达最大吞吐量)-1: 需等待ISR中的所有副本都成功写入后响应(最强的可靠性,但是ISR=1时不一定可靠)
2.2 broker(存不丢)
Kafka通过副本机制保证
2.3 消费者(消费不丢)
将Kafka的位移提交由自动改为手动
3. 如何保证顺序性
Kafka保证了单分区时有序的
3.1 单分区
消息发送到一个分区,由消费者的一个线程来消费
3.2 通过分区器
Kafka生产者发送消息时配置分区器,hash计算后发送到指定分区
4. 如何避免重复消费,或者说如何保证幂等性
4.1 哪些场景可能产生重复的消息
- 生产者重试
- 消费者位移提前
4.2 有哪些手段保证不重复
- 生产者不重试
- 消费者取消自动提交位移
- 做幂等
- Kafka 有一个幂等的配置
enable.idempotence:true- 消费幂等: 例如利用MySQL去重表、唯一索引、Redis唯一标识
- Kafka 有一个幂等的配置
消息投递的语义
- At Most Once ,最多投递一次,可能丢失但是不会重复传输,一般用于对消息可靠性没有太高要求的场景,比如一些允许数据丢失的日志报表、监控信息等
- At Least Once,至少会投递一次,消息绝不会丢失,但可能重复传输,大部分消息队列都支持,应用广泛
- Exacly Once,每条消息肯定会被传输且只传输一次
5. 如何处理消息积压
发生积压,说明生产速度大于消费速度
在消费者端,首先要排除bug,优化消费逻辑
临时进行服务端的扩容,增加分区和消费者,消费完后进行恢复
6. 消息集群高可用
Kafka集群,多副本机制,优先副本
Kafka的分区和副本分配遵循的原则
- 一个Topic的Partition数量大于Broker的数量,使得Partition尽量均匀分配到整个集群上
- 同一个分区,所有的副本要尽量均匀分配到集群中的多台Broker上
- 尽可能保证用一个分区下的主从副本,分配到不同的Broker上
7. 如何设计一个消息队列
7.1 生产者
生产者需要经历哪些才能发送(拦截器,序列化,分区器,累加器,sender线程)
7.2 传输
传输协议,RPC,序列化协议
7.3 消息队列的持久化、广播方式(推/拉)、集群
7.4 如何消费
8. Kafka的基础概念
整体体系架构由多个生产者,Kafka集群和多个消费者组成
一个主题Topic有n个分区Partition,每个分区有m个副本Replica,每个分区内有offset(位移/偏移量)
其中n是分区数,m是副本因子, Topic:Partition:Replica=1:n:m,offset是分区中的唯一标识
AR: 分区的所有副本ISR: 所有和leader副本保持一定程度同步的(包含leader)的副本OSR: 与leader副本滞后过多的副本
AR = ISR + OSR
HW: 高水位(偏移量),消费者只能拉去到高水位之前的消息LEO: 当前日子文件中下一条待写的offsetISR最小的LEO是分区的HW
9. Kafka为什么快
Broker(读-页缓存,写-顺序写,传输-零拷贝)
顺序写盘
文件追加写入消息,只能在日志文件尾部追加新消息,且不允许修改已写入的消息
页缓存
读磁盘时,先看待读的数据所在页是否在页缓存中,存在则返回;不存在则向磁盘中读,再到页缓存读;
写磁盘时先检查是否在页缓存中,若不存在则先在页缓存中添加页,脏页随OS写入磁盘
零拷贝
将数据直接从磁盘文件复制到网卡设备中,而不需要经过应用程序,减少内核态和用户态的切换
Linux中的
sendfile(),Java中的FileChanel.transferTo()
生产者
发送消息时,先写入到内存缓冲,直到多条消息组成一个Batch,经过网络通信将Batch发送,
内存缓冲池优化了GC
消费者
多个消费者并行消费
