Kafka常用面试题整理
Kafka 是什么?主要应用场景有哪些?
Kafka 是什么
kafka是一个多分区、多副本且基于zookeeper协调的分布式消息系统,是一个基于发布/订阅的消息系统。也是一个分布式流式处理平台。
LinkedIn 最早开发 Kafka 用于处理海量的日志,到后来逐步改进解决了丢失消息、不保证消息可靠性等问题后,最终在消息队列领域占据了一席之地。
流平台的三个功能
- 消息队列,发布和订阅消息流,类似消息队列,这也是 Kafka 也被归类为消息队列的原因。
- 容错的持久方式存储记录消息流,可以将消息持久化存储到磁盘,避免了消息丢失的风险。
- 流式处理平台,在消息发布的时候进行处理,kafka提供了一个完整的流式处理类库。
应用场景
- 代替传统的消息队列来进行,应用解耦,流量削峰,消息异步等
- 构建一个流处理程序处理数据流
- 日志聚合,将日志抽象为消息流等
和其他消息队列相比,Kafka的优势在哪里?
1.性能强悍,基于 Scala 和 Java 语言开发,设计中大量使用了批量处理和异步的思想,最高可以每秒处理千万级别的消息
2.生态好,Kafka 与周边生态系统的兼容性是最好的没有之一,尤其在大数据和流计算领域
队列模型和kafka消息模型
队列模型
队列模型中,生产者发送消息,消费者消费消息,队列作为消息的载体,一条消息只能被一个消费者消费,未被消费的消息将在队列中保存直到被消费或者超时。
可能产生的问题
由于使用队列(Queue)作为消息的载体,消息消费是一对一的,当消息被消费后,队列中不再存储,消息无法被复用,当生产者产生一条消息需要被多个消费者消费时(类似广播),队列模型是无法满足这一需求的,如果单独为每个消费者提供一个消息队列的话,会造成资源浪费,违背了使用消息队列的初衷。
kafka消息模型
发布-订阅(Pub-Sub)模型
发布-订阅模型主要是为了解决消息队列模型的问题.
Cluster>Broker>Topic>Partition
发布-订阅模型采用主题(Topic)作为消息的载体,类似与广播形式,也就是发布者发布一条消息,该消息通过主题传递给所有的订阅者。但是,订阅者在消息发布之前如果没有订阅相关主题是无法收到这个消息的。
kafka术语
- Producer-生产者 :
产生消息的一方。
- Consumer-消费者:
消费消息的一方。
- Cluster-集群:
一个Kafka Cluster里可以包含多个Kafka Broker 。
- Broker-代理:
一个Broker可以看做一个独立的Kafka实例。
Broker里又包含 Topic和 Partition两个概念。
一个Broker里可能包含一个或多个Topic。
- Topic-主题:
Producer将消息发送到特定的Topic,Consumer通过订阅特定的Topic来消费消息。
一个Topic可以包含多个Partition。
- Partition-分区
Partition 属于 Topic 的一部分。
同一个Topic下的Partition可以分布在不同的Broker上,这就表明,一个一个Topic可以横跨多个Broker
Kafka中没有队列这个概念,Partition有点类似于队列
- Kafka 中的 Partition(分区) 实际上可以对应成为消息队列中的队列
- 同一个主题下的分区可以在不同的代理中
Kafka的多副本机制与好处
Kafka的多副本机制
- Kafka中改的Partition中引入了多副本机制(Replica)
- Partition中的的多个副本中会有一个交Leader的副本,其他副本成为Follower。
- 我们发送的消息会被发送到Leader副本中,然后其他Follower副本才能从leader中同步消息。
- 生产者与消费者只与Leader副本发生交互,其他Follower副本知识Leader副本的拷贝,只是为了保证消息存储的安全性。
- 当Leader副本出现故障,会从Follower副本中选举一个Leader,但是如果Follower中的消息与Leader中不同步,则参加不了竞选。
Kafka的多分区以及多副本机制好处
- Kafka通过给特定的Topic指定多个Partition,而各个Partition又可以分布在不同的Broker上,这极大的提高了它的并发能力(负载均衡)。
- Partition中的多副本(Replica)机制,则保证了消息存储的安全性,提高了容灾能力,但是也占空间,也许这就是消息持久化到磁盘的体现?。
Zookeeper在Kafka中的作用
kafka三个问题,消息顺序,消息丢失,消息重复
Kafka 如何保证消息的消费顺序
Kafka中添加消息到分区(Partition)都采用尾插法,Kafka中只能保证在分区中的消息有序。也就是说如果不指定消息发送的分区,消息的消费顺序就会受影响。
对于保证消息的消费顺序
- 一个Topic里只有一个Partition(ps:丧失了kafka的高并发的优势)
- 在发送消息时指定key/partition
ps:Kafka 中发送 1 条消息的时候,可以指定 topic, partition, key,data(数据) 4 个参数。如果你发送消息的时候指定了 Partition 的话,所有消息都会被发送到指定的 Partition。并且,同一个 key 的消息可以保证只发送到同一个 partition,这个我们可以采用表/对象的 id 来作为 key 。
Kafka 如何保证消息的消费不丢失
Producer端
- 把异步的消息发送改为同步,实时了解消息发送的结果。
- 添加异步或者调函数,监听消息发送的结果,乳沟失败可以在回调中充实
- Producer中提供了retries机制,如果因为网络问题,或者broker故障 导致发送失败,就是重试
Broker端 (把消息持久化到磁盘)
但是Kafka为了提高性能,采用的是异步批量,存储到磁盘的机制,就是有一定的消息量和时间间隔要求的,刷磁盘的这个动作是操作系统来调度的,如果在刷盘之前系统就崩溃了,就会数据丢失。
Consumer端
- 基本不太可能出现问题,除非出现没有消费完就提交了offset,这个我们可以重新调整offset的值,来实现重新消费。d
Kafka 如何保证消息的消息不重复消费
这种情况可能是消费者消费了消息,但是消费者服务器挂了或者网络问题,没有来的及提交offset,此时就会发生重复消费。
ps: offset,消息位移,它表示分区中每条消息的位置信息,是一个单调递增且不变的值。换句话说,offset可以用来唯一的标识分区中每一条记录。消费者消费完一条消息记录之后,需要提交offset来告诉Kafka Broker自己消费到哪里了。
ps: 幂等性:一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
解决方法
- 依靠一些数据库做幂等校验,如Mysql的主键,Redis的set,是最有效的方法。
- 将 enable.auto.commit 参数设置为 false,关闭自动提交,开发者在代码中手动提交 offset。
什么时候提交offset合适?
- 处理完消息再提交:依旧有消息重复消费的风险,和自动提交一样拉取到消息即提交:会有消息丢失的风险。
- 允许消息延时的场景,一般会采用这种方式。然后,通过定时任务在业务不繁忙(比如凌晨)的时候做数据兜底。