消息积压:业务突然增长,导致消息消费不过来怎么办?

消息积压:业务突然增长,导致消息消费不过来怎么办?

消息积压指消息生产速度大于消费速度,导致消息在broker上存放。消息积压可能导致消息很久才被消费。对于时效性有要求的业务是不可容忍的。

消费者和分区的关系

  • Kafka中,一个分区只能有一个消费者,但一个消费者可以同时消费多个分区。
  • 如果有N个分区,最多有N个消费者,再增加消费者也不能提供消费速度
  • 如果不足N个消费者,一些消费者会从多个分区拉数据

这种设计无法通过无限增加消费者来解决消息积压问题。如果没有这种限制就不会有消息积压了

确定分区数量

  • 分区数量要保证生产者不会阻塞,同时消费者来的及消费消息
  • 可以通过压测或者观测消息集群性能来确定

解决方案

解决消息积压要区分是临时积压还是永久积压

  • 临时积压:是突然来的流量,导致消费者一时半会跟不上
  • 永久积压:则是消费者消费速率跟不上生产速率
  • 如果临时积压,并且消费者处理的时间可以接受,可以不解决
  • 如果接受不了,或是永久积压。就需要尝试解决。最简单的方案是增加消费者到分区数量一致

增加分区

如果消费者和分区数量一致可以尝试增加分区。

  • 增加新分区意味着可以增加新的消费者来增速

创建新的topic

有时候公司不允许增加分区,可以考虑创建新的topic

  • 准备一个新topic,消费老topic的同时也消费新的topic。等老topic数据消费完后完全切换到新topic
  • 或者创建新topic,把老topic上的消息转发到新topic上。只需要启动消费者消费新topic就可以了

创建新topic的难点是究竟需要几个分区,最佳办法就是压测来确定

新分区计算方式:假设所有生产者QPS是3000。一个消费者处理的QPS是200,那么就是3000÷200=15。考虑业务增长或者突发流量可以使用18到20个分区

优化消费者性能

不能增加消费者和分区的时候,可以考虑优化消费者性能,大体两种思路

  • 消费者部署更好的实例上(不是我们能左右的)
  • 优化消费者消费逻辑
方案
  • 最开始考虑同一个业务的消息可能被不同的消费者消费,就引入了分布式锁
  • 后面通过主动选择目标分区使相同业务总把消息发到同一分区,确保同一时间只有一个消费者处理一个业务的消息,就可以去掉分布式锁,没有分布式锁就不会因为等待分布式锁而导致消费速率下降

聚合消息和批量操作

  • 这种方式适用于消费者可以改造成批量接口的场景
  • 可以考虑不改造生产者,只改造消费者
  • 把消费者改造成批量消费、批量提交偏移量
  • 比如消费者一次性拉去100条消息,构造批量处理请求。请求处理成功后,再提交偏移量

异步消费(核心解决方案)

  • 消费者弄一个消费线程,负责从消息队列拉消息。拉到的消息立刻转发给一个线程池,线程池有一些工作线程处理消息。
  • 注意消息丢失的问题
消息丢失
  • 消息丢失:指消费者线程取出消息后,要消费下一条就要先提交当前这条。这时可能出现一个问题:消费者线程提交了,但是工作线程还没处理就挂了。因为已经提交了,就算重启也是从下一条开始消费
  • 解决方案:可以考虑批量提交的方法。消费者线程一次拉一批消息。比如说10条,然后不是立刻提交这10条消息,而是开十个线程并行处理这10条消息,等10条消息都处理完,再批量提交
  • 问题:批量提交效果很好,但是会带来重复消费和部分失败的问题
重复消费

消费者线程拉去一批消息后,如果还没提交就挂了。当消费者恢复后,就会拉取同一批继续消费。

  • 解决方案:保证处理消息的逻辑是幂等的。这样即使宕机导致消费被消费还没提交,也可以保证下次恢复时,重复处理不会引起业务问题
部分失败

要保证部分失败不会影响继续向前消费

  • 第一种做法是要求工作线程立即重试。比如重试三次,或者用一个新的异步线程来重试
  • 第二种做法是把消费失败的消息丢回消息队列,后面轮到它又会被处理,相当于重试
相关推荐
小信丶27 分钟前
@EnableTransactionManagement注解介绍、应用场景和示例代码
java·spring boot·后端
To Be Clean Coder35 分钟前
【Spring源码】createBean如何寻找构造器(四)——类型转换与匹配权重
java·后端·spring
-孤存-1 小时前
SpringBoot核心注解与配置详解
java·spring boot·后端
2301_818732062 小时前
项目启动报错,错误指向xml 已解决
xml·java·数据库·后端·springboot
小王不爱笑1322 小时前
SpringBoot 整合 Ollama + 本地 DeepSeek 模型
java·spring boot·后端
短剑重铸之日4 小时前
《设计模式》第七篇:适配器模式
java·后端·设计模式·适配器模式
树码小子5 小时前
SpringIoC & DI (1):IOC介绍 & Spring IoC使用 & DI
java·后端·spring
墨染青竹梦悠然7 小时前
基于Django+vue的图书借阅管理系统
前端·vue.js·后端·python·django·毕业设计·毕设
怪兽毕设7 小时前
基于Django的洗衣服务平台设计与实现
后端·python·django·洗衣服务平台
程序员泠零澪回家种桔子7 小时前
微服务日志治理:ELK 栈实战指南
后端·elk·微服务·云原生·架构