一、使用消息队列的好处有哪些?
解耦
削峰控流
异步
可恢复
二、消息队列的模式有哪两种?Kafka属于哪一种?
1.点对点模式
2.发布/订阅模式
Kafka属于点对点模式,消费者主动去队列中获取消息。
三、Kafka的基本架构?由哪些部分或者角色组成?
1.Producer、Consumer、Message
Producer 消息的生产者
Consumer 消费者,多个消费者可以组成一个Consumer Group
Message 消息,信息本身
2.Broker、Topic、Partition
Broker 集群场景下,一个Broker即是一个kafka实例,一台服务器上会有一个或者多个Broker,每个Broker会有一个第一无二的编号。Kafka集群中的其中一个Broker会被选举为Controller,主要负责Partition管理和副本状态管理,也会执行类似于重分配Partition之类的管理任务。如果当前的Controller失败,会从其他正常的Broker中重新选举Controller。
Topic 可以理解成消息的分类、或者频道
Partition 分区,一个Topic分做多个分区,分区的作用是做负载,提高Kafka的吞吐量,Partition的表现形式就是一个个文件夹。这个文件夹里会有一堆用偏移量offset标识的.log文件、.index文件和.timeindex文件。
3.Replication、Leader、Follower
这是一个相对的概念,主备关系。一个Partition会有很多个Replication,当Leader发生故障的时候,会选择一个Follower上位作为Leader,副本的数量不能大于Broker的数量,而且Leader与Follower绝对不在同一个Broker上。
4.zookeeper
kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。
四、Kafka原理?怎么写?怎么读?持久化是怎么做的?详细说明
1.写入数据
生产者生产消息时,总是往Leader写入。
①从集群中获取分区的Leader
②Producer将消息发送给Leader
③Leader将消息写入本地文件
④Follower从Leader那里pull消息
⑤Follower将消息写入后给Leader发ACK
⑥Follower收到ACK后给Producer发送ACK
每条消息追加到分区中,顺序写入,所以同一分区数据是有序的
消息在写入时可以指定分区;如果没有指定,则通过数据的key的值hash出一个分区;如果既没有指定分区数据又没有设置key,则会轮询出一个分区。
ACK应答机制可以设置参数来确认kafka是否收到数据。这个参数可以是0, 1, all
- 0代表生产者发送数据不用等集群返回,不保证消息发送成功。
- 1代表只要Leader应答就继续发送下一条,只能确保Leader成功接收到消息。
- -1(也就是all)代表Leader以及集群所有Follower都完成同步备份。
从0到all,效率由高到低,安全性由低到高。
2.保存数据
前面说过Partition的体现就是一个个的目录。Partition目录下还分成不同组的segment文件,segment包含.log文件、.index文件、.timeindex文件。log文件保存消息体本身。index文件和timeindex文件保存索引,前者通过偏移量也就是offset索引,后者通过时间戳索引,两者都是稀疏索引(没有把所有Message的索引都保存下来)
Message有三个重要组成部分
offset: 占8byte的有序id号
消息大小:占用4byte,描述消息大小
消息体:实际的消息数据(被压缩过)
被消费的消息不会立刻删除,kafka会保存所有的消息,不管是否被消费。
kafka的删除策略主要有两种
1.基于时间,默认7天
2.基于大小
3.消费数据
消费者可以组成消费者组,同一组消费者的数量小于等于Partition的数量,当消费者数量等于partition数量时,效率最高。
不同的消费者消费不同分区中的内容,通过并发提高效率。
查找要消费的数据,建立在offset有序的基础上,通过segment+有序offset+稀疏索引+二分查找+顺序查找来高效查找数据。
五、Kafka高性能的原因?
1.顺序写
省去寻址时间,大多数情况下磁盘顺序写比内存随机写速度还要快
2.零拷贝
正常情况下,先把数据读到内核空间,在从内核空间把数据读到用户空间,然后在调操作系统的io接口写到内核空间,最终在写到硬盘中。
Kafka是这样做的,直接在内核空间流转io流,所以kafka的性能非常高
3.批量处理
合并小的请求,然后以流的方式进行交互,直顶网络上限。
六、kafka与其他消息中间件(RabbitMQ、RocketMQ)做比较?
RabbitMQ、RocketMQ、Kafka对比
特性 | RabbitMQ | RocketMQ | Kafka |
---|---|---|---|
实现语言 | Erlang | Java | Scala |
单机吞吐量 | 万级 | 10万级 | 10万级 |
topic数量对吞吐量的影响 | - | 影响较小,topic可以达到几百甚至几千 | 影响较大,topic到几百个时,吞吐量会大幅度下降 |
时效性 | 微秒级,延迟低是RabbitMQ的一大特点 | 毫秒级 | 毫秒级以内 |
可用性 | 高,主从架构 | 非常高,分布式 | 非常高,分布式 |
消息可靠性 | - | 经过参数优化配置,可以做到0丢失 | 同RocketMQ |
功能支持 | 并发能力强,性能好,延时第 | MQ功能较为完善,扩展性好 | 只要支持简单的MQ功能,不支持消息查询、回溯等 |
RocketMQ社区活跃度不高,支持的客户端语言较少,目前支持java、c++,其中c++不成熟。
所以中小型公司,技术实力较为一般,技术挑战不是特别高,用 RabbitMQ 是不错的选择;大型公司,基础架构研发实力较强,用 RocketMQ 是很好的选择。
如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。
七、Kafka面试题
1.kafka中的ISR, AR是什么?ISR伸缩是什么?
AR - assigned replicas 分区中的所有副本
ISR - in-sync replicas 与Leader保持一定程度同步的Follower
此外,还有OSR - out-sync replicas
AR=ISR+OSR
前面所说的“一定程度”是指可以忍受的滞后范围,这个范围可以通过参数进行配置。超出这个范围的Follower会被踢出ISR,放到OSR中,新加入的Follower也在OSR中。
2.kafka中的zookeeper是做什么的?
管理元数据,选举controller,检测broker是否存活
3.follower如何与leader同步数据?
简单来说就是利用了ISR机制。
Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。完全同步复制要求All Alive Follower都复制完,这条消息才会被认为commit,这种复制方式极大的影响了吞吐率。而异步复制方式下,Follower异步的从Leader复制数据,数据只要被Leader写入log就被认为已经commit,这种情况下,如果leader挂掉,会丢失数据,kafka使用ISR的方式很好的均衡了确保数据不丢失以及吞吐率。Follower可以批量的从Leader复制数据,而且Leader充分利用磁盘顺序读以及send file(zero copy)机制,这样极大的提高复制性能,内部批量写磁盘,大幅减少了Follower与Leader的消息量差。
4.kafka如何优化producer写入broker的速度?
- 增加partition
- 增加更多producer实例
- 如果是对可靠性要求较低,性能要求较高的场景,可以尝试将acks参数设置为1(只要leader应答就继续发送下一条)或者0(只管发送,不保证消息成功写入)
5.kafka unclean配置代表什么?会对spark streaming消费有什么影响?
如果unclean.leader.election.enable设置为true的话,不在ISR中的副本也可以参与选举,可能会存在丢数据的情况。这种情况下,spark streaming在消费过程中拿到的end offset会变小,导致spark streaming job挂掉。
6.如果leader crash的时候,ISR为空怎么办?
两种情况:
- 如果unclean参数为true,会从OSR中的副本进行选举,产生新的leader,可能会出现消息不一致的情况,可靠性比较低
- 如果unclean参数为false,会一直等待leader恢复,可用性比较低。
7.kafka中的消息是否会丢失或者重复消费?
1.消息丢失
可以从消息发送和消息消费两个方面来分析。
消息发送
当acks配置为0时,当网络异常、缓冲区塞满了的情况下,会出现消息丢失
当acks配置为1时,leader确认消息成功接收之后挂掉,没来得及同步到follower,然后重新选举产生新的leader,也会导致消息丢失
消息消费
kafka消费者有两个消费接口:Low-level API和High-level API
Low-level API:消费者自己维护offset等值,可以实现对消费数据的完全控制
High-level API:封装了对parition和offset的管理,使用简便
如果使用High-level API,消费者pull到消息,并提交新消息的offset,没来得及消费就挂掉了,恢复后再次消费时就会出现之前没有消费的消息消失的现象。
2.重复消费
将消息唯一标识保存到外部介质中,每次消费判断是否处理过即可。