Kafka的几个新人面试题

讲一下什么是Kafka

首先引入这样一个场景:A服务可以发送200qps(Queries Per Second,是指每秒查询率),而B服务可以处理100qps。很显然,B服务很可能会被A服务压垮掉。怎么为了保证B不被压垮的同时还能处理A消息,没有什么是不能通过一层中间件解决的,如果有,那就再加一层。

开始很容易想到,可以在B服务中增加一个队列,其实就是个链表,B服务根据自己的消费能力,消费链表中的消息。每个节点用Offset记录,消费过程不断更新自己的Offset值。但就会出现来不及处理的消息都堆积到内存中,如果B重启,就会丢失消息。

所以可以把队列挪出来,变成一个单独的进程。也就成了简陋的消息队列。像A这样生产消息的为生产者,B消费消息的为消费者。但这太简陋了,高性能高可用高扩展,他都不沾边。

高性能

对于高性能,由于B消费能力有限,消息队列会堆积消息,就可以通过扩张多个消费者来加快消费,同理可以扩展多个生产者加快生产消息。但他们都同时竞争同一个消息队列,就会导致其他人等待浪费时间。

就可以分为多个消息队列,引出topic概念,将消息进行分类。生产者和消费者都去对应其中的topic。

但消息队列可能还是有点长,就可以分段,进行分区partition的概念诞生,每个消费者负责一个partition。

高扩展

对于高扩展,由于分区变多,都放在同一台机器,就会导致内存和cpu过高,影响整体系统性能,就可以引入多台机器,每个机器代表一个Broker。将分区分散部署到各个Broker中,就可以缓解单台服务器压力。

高可用

对于高可用,由于分区可能挂了,就会导致数据丢失,所以可以进行数据备份,主从复制,Leader负责和消费者生产者读写请求,follower负责同步Leader数据。这样就算Leader挂了,也可以顶替上去。

持久化和过期策略

也有可能所有Broker都挂了,就需要将数据放入内存,持久化到磁盘中。即使全部Broker都挂了,数据也不会丢失。但磁盘内存有限,就需要加个保留策略,retention policy(比如磁盘超过一定数据,或消息放置超过一定时间,就会被清理掉)

consumer group

到这里,这个消息队列好像就挺完美了。但其实还有个问题,按现在的消费方式,每次新增的消费者只能跟着最新的消费 Offset 接着消费。 可以给消息队列加入消费者组(consumer group)的概念,B 和 C 服务各自是一个独立的消费者组,不同消费者组维护自己的消费进度也就是Offset值,互不打搅。

基础架构

Producer(生产者):产生消息的一方

Consumer(消费者):消费消息的一方

Consumer Group(消费者组):一组存在多个消费者,消费者组间互不影响,所有消费者都可能属于某个消费者组,算一个逻辑订阅者。分区中的消息只能被一个消费者消费

Broker(代理,经纪人):一台Kafka服务器就算一个Broker,多个Broker组成Kafka Cluster(集群)

Topic(主题):生产者消费者都面向一个主题

Partition(分区):为了实现扩展性,一个Topic可能分布到多个Broker,一个Topic可以分为多个Partition,每个Partition相当于有序队列。

  • Replica:副本Replication,为保证集群中某个节点发生故障,节点上的Partition数据不丢失,Kafka可以正常的工作,Kafka提供了副本机制,一个Topic的每个分区有若干个副本,一个Leader和多个Follower

  • Leader:每个分区多个副本的主角色,生产者发送数据的对象,以及消费者消费数据的对象都是Leader。

  • Follower:每个分区多个副本的从角色,实时的从Leader中同步数据,保持和Leader数据的同步,Leader发生故障的时候,某个Follower会成为新的Leader。

如何保证消息的消费顺序

Kafka真正存储消息的地方是Partition,每次添加消息到Partition时,都会采用尾加法,在消费时,会进行偏移量的提交,用于追踪每个消费者在各个分区下消费的位置。也可以定时提交解决重启或故障问题。保证了分区中消息的有序。

但分区间消息顺序不一定,就需要我们在发送时指定一些参数,Topic,Partition,key,data来保证消息消费的顺序。

如何保证消息不丢失

首先是 Producer 端,需要确保消息能够到达 Broker 并实现消息存储,在这个层面,有可能出现网络问题,导致消息发送失败,所以,针对 Producer 端,可以通过 2 种方式来避免消息丢失

  • Producer 默认是异步发送消息,这种情况下要确保消息发送成功,有两个方法

    a. 把异步发送改成同步发送,这样 producer 就能实时知道消息发送的结果。

    b. 添加异步回调函数来监听消息发送的结果,如果发送失败,可以在回调中重试。

  • Producer 本身提供了一个重试参数 retries,如果因为网络问题或者 Broker 故障导致发送失败,Producer 会自动重试。

然后是 Broker 端,Broker 需要确保 Producer 发送过来的消息不会丢失,也就是只需要把消息持久化到磁盘就可以了。

但是,Kafka 为了提升性能,采用了异步批量刷盘的实现机制,也就是说按照一定的消息量和时间间隔来刷盘,而最终刷新到磁盘的这个动作,是由操作系统来调度的,所以如果在刷盘之前系统崩溃,就会导致数据丢失。

Kafka 并没有提供同步刷盘的实现,所以针对这个问题,需要通过 Partition 的副本机制和 acks机制来一起解决

在这样的一种机制的基础上,kafka 提供了一个 acks 的参数,Producer 可以设置 acks 参数再结合Broker 的副本机制来群共同保障数据的可靠性。

acks 有几个值的选择。

  • acks=0, 表示 producer 不需要等 Broker 的响应,就认为消息发送成功,这种情况会存在消息丢失。

  • acks=1, 表示 Broker 中的 Leader Partition 收到消息以后,不等待其他 Follower Partition 同步完,就给 Producer 返回确认,这种情况下 Leader Partition 挂了,会存在数据丢失。

  • acks=-1,表示 Broker 中的 Leader Parititon 收到消息后,并且等待 ISR 列表中的 follower 同步完成,再给 Producer 返回确认,这个配置可以保证数据的可靠性。

最后,就是 Consumer 必须能消费到这个消息,实际上,我认为,只要 producer 和 broker 的消息可靠得到了保障,那么消费端是不太可能出现消息无法消费的问题,除非是 Consumer 没有消费完这个消息就直接提交了,但是即便是这个情况,也可以通过调整 offset 的值来重新消费。

为啥分区只能由一个消费者组的一个消费者消费

同一时刻,一条消息只能被组中一个消费者消费。若两个消费者负责同一个分区,就意味着两个消费者同时读取分区中消息,由于消费者自己可以控制读取消息的Offset,就有可能,导致冲突情况。

相当于多线程去处理一个消息,造成消息处理的重复,且不能保证消息的顺序。

借鉴B站:Mic,小白debug

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值