消息丢失
要解决消息不丢的问题,要从整个链路去看,只有保证全链路的不丢失,才能完全保证消息不丢
生产者
生产者保证消息不丢的方式,网上的教程很多,无非就是配置ACK级别,增加重试,非常重要的消息,可以尝试无限重试(个人并不觉得是个好的解决方案),感觉重试一定次数之后,仍然失败的消息,持久化即可,后续认为介入处理或者定时任务进行重试处理,这样的话需要考虑消息量大的时候,持久化方式的承受能力,一般mysql数据库的承受能力约千TPS级别(也是要看机器配置,可以参考一下腾讯云做的性能测试)。
broker端
默认情况下,当 acks=all 时,一旦所有同步副本ISR都收到消息,就会发生确认。
broker端如何保证数据不丢失,这个可以参考一些书籍,如深入理解Kafka:核心设计与实践原理,一般是刷盘前宕机导致数据丢失,如果ack=all的时候,按理来说这种丢失概率很小,只有未刷盘前,leader和整个ISR都挂掉才可能出现数据丢失,否则应该不会出现(有点忘了TODO)
消费者端
默认的消费者会批量拉取消息,然后自动提交位移,具体的拉取量可以自己配置。
如果是同步的消费方式,消息拉过来,消费了一部分消息之后消费者重启或者重新部署了之后,位移是没有提交的,这时候重启之后就会出现重复消费的情况,这个消费端自己做幂等即可,幂等实现方案包括常见的数据库唯一索引等,网上一大堆。
但是常见的消费模型是异步的,也就是说一个消费线程拉取消息,然后多个线程(线程池)去并行消费消息,异步消息的消费线程不会阻塞拉取线程,因此拉取完消息,就自动提交了位移,这样常见的问题就是消费者会不断的拉取消息,消息量大的情况下,如果不做处理,会导致潜在的OOM异常。
常见的解决方案是消费端进行限速(别的方案如broker端限速