MQ 问题集合

KAFKA 当前版本 2.2.1 项目使用 2.X

朱小厮kafka面试题整理

问题

答案

kafka acks参数对消息持久化的影响

参考:https://mp.weixin.qq.com/s/IxS46JAr7D9sBtCDr8pd7A

acks参数,是在KafkaProducer,也就是生产者客户端里设置

acks=0

只要把消息发送出去,不管那条数据有没有在Partition Leader上落到磁盘,我就不管他了,直接就认为这个消息发送成功了。

影响:Partition Leader所在Broker就直接挂,会导致这条消息就丢失了

acks = 1 默认的设置

只要Partition Leader接收到消息而且写入本地磁盘了,就认为成功了,不管他其他的Follower有没有同步过去这条消息了。

影响:Partition Leader刚刚接收到消息,Follower还没来得及同步过去,结果Leader所在的broker宕机了,此时也会导致这条消息丢失

acks=all

Partition Leader接收到消息之后,还必须要求ISR列表里跟Leader保持同步的那些Follower都要把消息同步过去,才能认为这条消息是写入成功了。

影响:如果你的Partition只有一个副本,也就是一个Leader,任何Follower都没有,也会导致数据丢失

kafka参数调优

参考:

https://mp.weixin.qq.com/s/YLrGg-jx5ddmHECmdccppw

Kafka生产端的示例代码

buffer.memory KafkaProducer本地的内存缓冲,默认值是32MB。内存缓冲里大量的消息会缓冲在里面,形成一个一个的Batch,每个Batch里包含多条消息。然后KafkaProducer有一个Sender线程会把多个Batch打包成一个Request发送到Kafka服务器上去。避免了一条消息一次网络请求。从而提升了吞吐量,即单位时间内发送的数据量。

设置太小:内存缓冲快速被写满,Sender线程来不及把Request发送到Kafka服务器,会阻塞用户线程

设置太大:浪费内存缓冲

方案:结合自己的实际情况来进行压测

 

batch.size 多大数据打包为一个Batch就可以发送出去

设置太大:数据老是缓冲在Batch里迟迟不发送出去,发送消息的延迟就会很高

设置太小:发送频率太高,降低整体吞吐量

linger.ms 消息一旦写入一个Batch,最多等待这么多时间,他一定会跟着Batch一起发送出去,要配合batch.size一起来设置

max.request.size 每次发送给Kafka服务器请求的最大大小,同时也会限制你一条消息的最大大小也不能超过这个参数设置的值

retries和retries.backoff.ms决定了重试机制,也就是如果一个请求失败了可以重试几次,每次重试的间隔是多少毫秒

acks 见上

Kafka如何通过精妙的架构设计优化JVM GC问题?

参考来源:https://mp.weixin.qq.com/s/XheJNFr5iEVCptZNw6c2oQ

Batch里的数据都发送过去了,现在Batch里的数据应该怎么处理?

Kafka客户端内部用了缓冲池的机制

缓冲池里会有很多的内存块,需要创建一个新的Batch,就从缓冲池里取一个内存块就可以了,如果Batch被发送到Kafka服务器了,此时Batch底层的内存块就直接还回缓冲池就可以了。

 

消费到的消息处理失败怎么办?

参考:https://mp.weixin.qq.com/s/jbCZ9zMvOtBR2xNB4gtOHg

死信队列的使用:处理失败的消息

消息处理失败了之后,MQ就会把这条消息转入提前设置好的一个死信队列中。

消费者恢复正常后,这个后台线程就从死信队列消费出

简述一下Kafka中的分区分配?

参考:https://mp.weixin.qq.com/s/cr_IVoAVcUpKJ5kqFbpTPw

生产者的分区分配 为每条消息指定其所要发往的分区

  1. 生产者指定所发往的分区,消息ProducerRecord中指定了partition字段

  2. 没有指定partition字段,那么就需要依赖分区器,根据key这个字段来计算partition的值(MurmurHash2 hash算法)。分区器的作用就是为消息分配分区

key不为null,那么默认的分区器会对key进行哈希,那么计算得到的分区号会是所有分区中的任意一个

key为null,那么消息将会以轮询的方式发往主题内的各个可用分区

 

消费者的分区分配 为消费者指定其可以消费消息的分区

消费者的分区分配而言,Kafka自身提供了三种策略,分别为RangeAssignor、RoundRobinAssignor以及StickyAssignor,可以通过实现ParitionAssignor接口来自定义分区分配策略。

 

broker端的分区分配

为集群制定创建主题时的分区副本分配方案,即在哪个broker中创建哪些分区的副本。

创建主题时,如果使用了replica-assignment参数,那么就按照指定的方案来进行分区副本的创建;

如果没有使用replica-assignment参数,那么就需要按照内部的逻辑来计算分配方案了。

Kafka中的选举时怎么回事?

 

控制器的选举

在Kafka集群中会有一个或多个broker,其中有一个broker会被选举为控制器(Kafka Controller),它负责管理整个集群中所有分区和副本的状态等工作。

Kafka Controller的选举是依赖Zookeeper来实现的,在Kafka集群中哪个broker能够成功创建/controller这个临时(EPHEMERAL)节点他就可以成为Kafka Controller。

 

分区leader的选举

分区leader副本的选举由Kafka Controller 负责具体实施。

当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要执行leader的选举动作。

基本思路是按照AR集合中副本的顺序查找第一个存活的副本,并且这个副本在ISR集合中。

 

消费者相关的选举

组协调器GroupCoordinator需要为消费组内的消费者选举出一个消费组的leader,这个选举的算法也很简单,分两种情况分析。

如果消费组内还没有leader,那么第一个加入消费组的消费者即为消费组的leader。

如果某一时刻leader消费者由于某些原因退出了消费组,那么会重新选举一个新的leader,这个重新选举leader的过程又更“随意”了

Kafka如何实现高吞吐?

参考:

https://mp.weixin.qq.com/s/sCRC5h0uw2DWD2MixI6pZw

  • 读写文件依赖OS文件系统的页缓存,而不是在JVM内部缓存数据,利用OS来缓存,内存利用率高

  • sendfile技术(零拷贝),避免了传统网络IO四步流程

  • 支持End-to-End的压缩

  • 顺序写磁盘以及常量时间get、put消息

  • Partition 可以很好的横向扩展和提供高并发处理

  • Batch机制 及 request机制

Kafka partition还能细分吗?

参考:

https://www.infoq.cn/article/depth-interpretation-of-kafka-data-reliability

每个 partition(目录) 相当于一个巨型文件被平均分配到多个大小相等的 segment(段) 数据文件中(每个 segment 文件中消息数量不一定相等)这种特性也方便 old segment 的删除,即方便已被消费的消息的清理,提高磁盘的利用率。

 

segment 文件由两部分组成,分别为“.index”文件和“.log”文件,分别表示为 segment 索引文件和数据文件。

为什么Kafka不支持读写分离?

Kafka 读、写都是走leader 主写主读

参考:

为什么Kafka不支持读写分离

 

主写从读问题:数据一致性问题(一段时间内主、从数据不一致);延时问题(主从同步过磁盘延时高)

 

Kafka 只支持主写主读有几个优点:

简化代码的 实现逻辑,减少出错的可能 ; 没有延时的影响 ; 不会出现数据不一致情况 ; 将负载粒度细化均摊,与主写从读相比,不仅负载效能更好,而 且对用户可控;

Kafka中的事务、幂等

参考:

Kafka中的事务是什么样子的

kafka开启幂等性功能 : 生产者 设置参数 enable.idempotence true

如何实现幂等性: 引入 producer id(简称PID,新的生产者实例在初始化的时候都会被分配一个PID)和序列号(sequence number)。对于每个PID,消息发送到的每一个分区都有对应的序列号,这些序列号从0开始单调递增。生产者每发送一条消息就会将对应的序列号的值加1。 只能保证单分区的幂等

 

事务:生产者提供唯一 transactionalId,与PID一一对应,获取一个单调递增的producer epoch;具有相同transactionalId的新生产者实例被创建且工作的时候,旧的且拥有相同transactionalId的生产者实例将不再工作

事务相关方法:initTransactions() beginTransaction() sendOffsetsToTransaction() commitTransaction() abortTransaction()

消费端事务: isolation.level 设置事务隔离级别

消息类型:普通消息,控制消息(ControlBatch,记录是否是事务消息以及事务的状态)

Kafka日志清理策略

参考:

Kafka日志清理

Kafka中每一个分区partition都对应一个日志文件,日志文件又可以分为多个日志分段文件

两种日志清理策略: log.cleanup.policy delete删除 compact压缩

  1. 日志删除(Log Deletion):按照一定的保留策略来直接删除不符合条件的日志分段。

  2. 日志压缩(Log Compaction):针对每个消息的key进行整合,对于有相同key的的不同value值,只保留最后一个版本。

日志删除策略

基于时间(默认7天过期):查找过期的日志分段文件 先查索引修改时间,再查文件修改时间;须要保证有一个活跃的日志分段activeSegment;日志分段文件添加上“.deleted”的后缀,最后由定时任务执行删除,默认1分钟执行一次

基于日志大小:当前日志的大小是否超过设定的阈值retentionSize

基于日志起始偏移量:小于logStartOffset可以删除

kafka 消息格式演变

一文看懂Kafka消息格式的演变

 

offset:用来标志它在partition中的偏移量 逻辑值

message size:表示消息的大小 V0版本消息最小14B

Record : 消息实体信息

  1. crc32(4B):crc32校验值。校验范围为magic至value之间。

  2. magic(1B):消息格式版本号,此版本的magic值为0。

  3. attributes(1B):消息的属性。总共占1个字节,低3位表示压缩类型:0表示NONE、1表示GZIP、2表示SNAPPY、3表示LZ4(LZ4自Kafka 0.9.x引入),其余位保留。

  4. key length(4B):表示消息的key的长度。如果为-1,则表示没有设置key,即key=null。

  5. key:可选,如果没有key则无此字段。

  6. value length(4B):实际消息体的长度。如果为-1,则表示消息为空。

  7. value:消息体。可以为空,比如tomnstone消息。

  8. timestamp 消息的时间戳 V1 才有

kafka中延时操作

生产者中没数据了消费者会一直拉吗?

Kafka延迟操作:读日志文件,如果没有足够的消息,会创建一个延时拉取操作,以等待拉取到足够数量的消息

延时操作:超时时间(超时时间内完成则正常返回) ,触发时机(超时触发或外部事件,外部事件可能是HW增长)

Kafka的用途有哪些?使用场景如何?

异步处理 、解耦、削峰、提速

消息,网站活动追踪,监测指标,日志聚合

Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么?

LEO , HW

ISR:In-Sync Replicas 副本同步队列
AR:Assigned Replicas 所有副本
ISR是由leader维护,follower从leader同步数据有一些延迟,任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。

LEO,LogEndOffset 的缩写,表示每个 partition 的 log 最后一条 Message 的位置

HW 俗称高水位,HighWatermark 的缩写,取一个 partition 对应的 ISR 中最小的 LEO 作为 HW,consumer 最多只能消费到 HW 所在的位置。

LSO:Last Stable Offset 对未完成的事务而言,LSO 的值等于事务中第一条消息的位置(firstUnstableOffset),对已完成的事务而言,它的值同 HW 相同

LW:Low Watermark 低水位, 代表 AR 集合中最小的 logStartOffset 值

Kafka中是怎么体现消息顺序性的?

kafka每个partition中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的。
整个topic不保证有序。如果为了保证topic整个有序,那么将partition调整为1.

kafka维护消费状态跟踪的方法

Topic被分成了若干分区,每个分区在同一时间只被一个consumer消费。这意味着每个分区被消费的消息在日志中的位置仅仅是一个简单的整数:offset。这样就很容易标记每个分区消费状态就很容易了,仅仅需要一个整数而已。这样消费状态的跟踪就很简单了。

kafka 消息丢失和消息重复处理方式

消息丢失解决方案:

首先对kafka进行限速, 其次启用重试机制,重试间隔时间设置长一些,最后Kafka设置acks=all,即需要相应的所有处于ISR的分区都确认收到该消息后,才算发送成功

 

消息重复解决方案:

消息可以使用唯一id标识

生产者(ack=all 代表至少成功发送一次)

消费者 (offset手动提交,业务逻辑成功处理后,提交offset)

落表(主键或者唯一索引的方式,避免重复数据)

业务逻辑处理(选择唯一主键存储到Redis或者mongdb中,先查询是否存在,若存在则不处理;若不存在,先插入Redis或Mongdb,再进行业务逻辑处理)

消息回溯

  1. 直接从partition中解析出timestmap,与回溯时间对比看是否需要回溯

  2. 改造index file,加入timestmap字段,然后查索引,定位需要回溯的消息

延时队列

kafka 不支持延迟队列,不过可以基于时间轮实现,或者借助于redis实现等

kafka rabbitMq

参考:

https://www.cnblogs.com/mengchunchen/p/9999774.html

kafka VS RocketMQ http://jm.taobao.org/2016/03/24/rmq-vs-kafka/

kafka : 性能好,吞吐量高,单机十万级别,高可用 缺点:消息重复消费

rabbitMq:RabbitMQ吞吐量稍微低些,实现的机制比较重;erlang开发,很难去看懂源码

RocketMQ(阿里):可靠性、性能都还不错,功能比较完善(阿里)

 

kafka VS RocketMQ

数据可靠性: kafka 只支持异步刷盘 RocketMQ支持同步刷盘和异步刷盘 (刷盘:内存写到磁盘)

性能对比: kafka 单机 TPS 百万级 RocketMQ 单机TPS 十万级

功能对比: 消费失败自动重试,事物消息,定时消息 kafka 不支持 RocketMQ支持

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值