怎么在Kafka上支持延迟消息?

怎么在Kafka上支持延迟消息?

延迟列队和延迟消息

  • 延迟列队是一种特殊队列,里面每个元素都有过期时间,如果没过期去拿元素会被阻塞,元素过期时就会拿到这个元素。可以说拿到的永远是最先过期的元素
  • 延迟消息指基于消息队列的延迟队列。消息不是被立刻消费,一段时间后才会被消费。到时间前,消息一直都被存储在消息队列的服务器上

支持延迟消息的消息队列

  • RabbitMQ:通过启动插件rabbitmq_delayed_message_exchange实现延迟消息。就是实现了一个exchange,exchange控制消息什么时候被投递到队列里

案例

利用定时任务调度

  • 开发一个定时任务平台,相当于业务发送者注册了一个任务,这个任务就是30分钟后发送一条消息到kafka上。之后消费者就能消费了
  • 缺点:定时任务中间件支撑不了高并发

分区设置不同延迟时间

  • 关键角色是delay_topic、延迟消费组

    • deleay_topic的分区被用来接收不同延迟时间的消息
    • 延迟消费组按照分区数量创建消费者,每个消费者一个分区。消费者每次读取一个消息,等延迟时间到后转发给biz_topic
介绍
  • 我们的方案比较简单,创建一个delay_topic,这个topic有N个分区,每个分区设置不同延迟时间。创建一个消费组消费这个delay_topic,消费者读取到消息后,根据延迟时间等待。等待完后发送到真正的topic上
亮点1
  • rebalance问题:消费者睡眠了,睡眠期间不消费消息,kafka会判定消费者崩溃,触发rebalance。rebalance之后,等消费者恢复过来,会被随机分配到别的分区,等于白睡了
  • 解决方案:利用kafka的暂停功能确保不触发rebalance,睡眠结束后再恢复。kafka的暂停功能相当于拉去0条数据,不是不拉数据。还是会发出poll调用,让kafka认为消费者还活着
亮点2
  • 一致性问题:实际就是再问biz_topic是先提交还是先转发,要抓住关键字后提交来回答
  • 一致性问题解决起来需要业务方配合,我们逻辑是到了延迟时间,就先转发biz_topic,然后再提交。也就是说转发biz_topic后,提交失败,下次还可以重试,biz_topic可能收到两条同样的消息。这种场景下只能要求消费者做到幂等
优缺点
  • 优点:足够简单,容易实现

  • 缺点:延迟时间必须预先设定好、分区之间负载不均匀

    • 延迟时间必须预先设定好:不支持随机延迟时间
    • 分区之间负载不均匀:很多业务只需要延迟3min。1min、10min数据就很少,可能造成消息积压问题

基于MySQL的亮点方案

实践中最好放弃随机延迟时间,绝大多数时间都用不上随机延迟时间。可以通过调整业务来适配固定的延迟时间

介绍

方案关键点是创建一个delay_topic ,业务发送者把消息发到这个topic,消息带上延迟的时间。然后有一个延迟消费者 ,消费delay_topic中的消息,转储到数据库 。还有一个延迟发送者 ,会轮询 数据库中的消息,把到时间的消息转发到真正的biz_topic中,完成后延迟发送者把数据库状态更新成已发送,最后业务消费者消费biz_topic

怎么支撑住高并发
  • 分区表:根据并发量选择按月份、周分、天分。历史分区直接清理

  • 表交替:准备两个表交替查写,交替查询。比如今天用tab0,明天用tab1,用tab1时就清空tab0,但延迟不能超过一天

  • 分库分表:并发非常高时考虑,只需要按照biz_topic的名字来分库分表,还可以叠加分区表和表交替提高性能

    • 隐患:不同topic并发度不一样,导致不同库不同表的压力差异很大
    • 解决方案:不考虑消息有序性,可以考虑轮询插入。查找只会按照发送时间来找,所以随机插入都没问题
    • 消息有序性:要保持消息有序性可以在分库分表时,确保同一个biz_topic的消息在同一张表,并且delay_topic也是按照biz_topic区分的,那么就可以保证延迟消息转发到biz上跟被发送到delay是一样的

批量操作

  • 还可以利用批量操作减轻MySQL的压力。延迟消费者可以消费了一批数据再批量插入到数据库,然后再提交这一批消息。延迟发送者可以发送一批数据后,再批量把这些消息更新为已发送
  • 批量操作可能会使数据一致性问题更严重。只要消费者可以做到幂等就可以了,比如用唯一索引
相关推荐
程序员岳焱3 小时前
Java 与 MySQL 性能优化:Java 实现百万数据分批次插入的最佳实践
后端·mysql·性能优化
麦兜*4 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
大只鹅4 小时前
解决 Spring Boot 对 Elasticsearch 字段没有小驼峰映射的问题
spring boot·后端·elasticsearch
ai小鬼头4 小时前
AIStarter如何快速部署Stable Diffusion?**新手也能轻松上手的AI绘图
前端·后端·github
IT_10245 小时前
Spring Boot项目开发实战销售管理系统——数据库设计!
java·开发语言·数据库·spring boot·后端·oracle
bobz9655 小时前
动态规划
后端
stark张宇5 小时前
VMware 虚拟机装 Linux Centos 7.9 保姆级教程(附资源包)
linux·后端
亚力山大抵6 小时前
实验六-使用PyMySQL数据存储的Flask登录系统-实验七-集成Flask-SocketIO的实时通信系统
后端·python·flask
超级小忍6 小时前
Spring Boot 中常用的工具类库及其使用示例(完整版)
spring boot·后端
CHENWENFEIc7 小时前
SpringBoot论坛系统安全测试实战报告
spring boot·后端·程序人生·spring·系统安全·安全测试