kafka性能高的原理:
- 消息追加写入磁盘,避免缓慢的随机IO
- zero 拷贝
- partition分区
kafka高可用:
- 副本机制(一个topic分布在不同的broker,同一个broker会有同个主题的部分分区,分区里面会包含副本或者leader,里面会有多个副本和leader)
什么时候消息会被删除:
持久化的逻辑,通过消息日志保存,日志包括多个日志段,消息追加到最新的日志段里面,当写满了之后,自动切份出息呢日志段出来。老的会根据定时任务定期去判断是否可以回回收。
kafka消费位移:
消费者回自己记录一个消费位移,这个位移会提交(老版本是zookeeper里面,优点broker可以无状态,便于伸缩,但是zk频繁的写不太适合,性能比较差),新版本放在kafka的一个内部主题,叫_consumerOffsets(消息格式是kV,Key 和 Value 分别表示消息的键值和消息体)
位移主题的 Key 中应该保存 3 部分内容:(groupID,topic,分区)
比如消息体还保存了位移提交的一些其他元数据,诸如时间戳和用户自定义的数据等。保存这些元数据是为了帮助 Kafka 执行各种各样后续的操作,比如删除过期位移消息等。
消费者提交消费位移的方法:1.手动,2.自动
自动创建位移主题的流程:消费者启动了,自动创建默认分区50,副本为3的消费位移topic
自动提交位移:假如设置了5秒提交一次位移位置,但是处理这一次pool()的数据花了7秒,不会没有处理完这一次pool的数据就去提交的,是处理完需要调用下一次的pool()的时候,检查有没有超过5秒,超过的话就提交,没超过就等待(这个参数也叫做最小提交位移间隔)。
问题:可能会重复消费。在自动提交位移之后,例如3秒后发生了rebalance,此时rebalance前3秒的数据都需要重复消费;
手动消费:可能造成重复消费(先消费了一部分,挂了,又重头开始拉数据);也有可能消息丢失(先提交了消费位移,再消费消息,这种可能处理过程挂了,没处理到的就丢掉了)。
主要问题还是重复消费:解决方法:业务里面根据做幂等;
手动消费的两种形式:
1.commitSync,阻塞,提交了之后才会结束block,影响tps,会重试,避免丢失数据;
删除过期位移主题的方法:
1.定期有一个定时线程检查位移主题,类似于mysql重写AOF的方法删除过期消息。
消费者群订阅topic的过程分配分区发生变化,需要重平衡:
触发条件:
- 消费者数量变化(增加或者减少(消费者定期会和corrdinator发送心跳,这个时间不要太小,经验是消费者设置是 6s超时,2秒每一次心跳包发送))
- 主题数发生变化
- 分区数量发生变化
重平衡过程:corrdinator对心跳包的回应通知到消费者开始重平衡
缺点:会停止消费,造成消息堆积;rebalance很慢;影响面很广,当前主题的所有消费者都会参重平衡,效率较低;
避免重平衡的最佳实践:
1.经验消费者设置是 6s超时,2秒每一次心跳包发送,这个参数设置合理点
2.消费者消费能力 两次消费时间间隔不要太小,max_pool_interval
3.排查GC
实现方式:
1.Coordinator提供重平衡,除此还会管理位移主题,组成员管理,元数据管理。
2.消费者组如何找到coodinator帮助重平衡(借助位移主题,找到对应的coodinator所在的broker,通过找到位移主题对应管理该消费者组的分区【partitionId=Math.abs(groupId.hashCode() % offsetsTopicPartitionCount)。】,然后在分区里面找到leader副本所在的broker)
3.
CommitFailedException异常以及解决方案:
消费数据的时间超过了max.poll.interval.ms
解决方案:
1.max.poll.interval.ms增大这个值
2.提高消费每一条数据的性能
3.每一次少拿一点数据
4.多线程消费
消息不丢失的专题:
怎么检测消息是否丢失:1.根据分布式链路追踪系统;2.消息队列的有序性检测,producer端,每发出一个消息,序号+1(假如多producer实例的话,需要附加上producer的标识),并且指定分区,在Consumer端每个分区单独检查这个序号的连续性,通过客户端的拦截器设置,consumer拦截器当中判断序号的连续性(优点:无入侵;)
1.生产者需要收到broker收到消息的确认消息,假如没收到话需要自动重发;
2.broker宕机之前,需要把消息持久化到磁盘才给producer发确认,除此之外消息至少发送到两个broker以上的才发确认消息;
3.消费者消费完消息再手动提交位移(重复的话,业务去重,或者消息的唯一key去查询这个消息是不是被消费了);