架构师基于Redis实现延时队列服务


一、背景

在业务发展过程中,会出现一些需要延时处理的场景,比如:
  1. 订单下单之后超过30分钟用户未支付,需要取消订单

  2. 订单一些评论,如果48h用户未对商家评论,系统会自动产生一条默认评论

  3. 点我达订单下单后,超过一定时间订单未派出,需要超时取消订单等。。

处理这类需求,比较直接简单的方式就是定时任务轮训扫表。这种处理方式在数据量不大的场景下是完全没问题,但是当数据量大的时候高频的轮训数据库就会比较的耗资源,导致数据库的慢查或者查询超时。所以在处理这类需求时候,采用了延时队列来完成。


二、几种延时队列

延时队列就是一种带有延迟功能的消息队列。下面会介绍几种目前已有的延时队列:
1.Java中java.util.concurrent.DelayQueue
优点:JDK自身实现,使用方便,量小适用
缺点:队列消息处于jvm内存,不支持分布式运行和消息持久化
2.Rocketmq延时队列
优点:消息持久化,分布式
缺点:不支持任意时间精度,只支持特定level的延时消息
3.Rabbitmq延时队列(TTL+DLX实现)
优点:消息持久化,分布式
缺点:延时相同的消息必须扔在同一个队列
根据自身业务和公司情况,如果实现一个自己的延时队列服务需要考虑一下几点:
* 消息存储
* 过期延时消息实时获取
* 高可用性


三、 基于Redis实现

1.0版本

  • 功能特性

* 消息可靠性,消息持久化,消息至少被消费一次
* 实时性:存在一定的时间误差(定时任务间隔)
* 支持指定消息remove
* 高可用性
  • 整体结构

架构师基于Redis实现延时队列服务

– Messages Pool所有的延时消息存放,结构为KV结构,key为消息ID,value为一个具体的message(这里选择Redis Hash结构主要是因为hash结构能存储较大的数据量,数据较多时候会进行渐进式rehash扩容,并且对于HSET和HGET命令来说时间复杂度都是O(1))
– Delayed Queue是16个有序队列(队列支持水平扩展),结构为ZSET,value为messages pool中消息ID,score为过期时间(分为多个队列是为了提高扫描的速度)
– Timed Task定时任务,负责扫描处理每个队列过期消息
  •  消息结构

每个延时消息必须包括以下参数:
* tags:消息过期之后发送mq的tags
* keys:消息过期之后发送mq的keys
* body:消息过期之后发送mq的body,提供给消费这做具体的消息处理
* delayTime:延时发送时间(默认,delayTime、expectDate有一个即可)
* expectDate:期望发送时间
  • 流程

架构师基于Redis实现延时队列服务
注:上图1、2、3或者2、3是一个事务操作
取出过期消息过程是通过一个外部定时任务每隔1min分钟去查询队列中过期的消息,然后发送mq && remove

2.0版本

1.0上有一个可改进的地方就是队列中过期的消息是通过定时任务触发查询。所有有了2.0
2.0版本在1.0上做了一个优化,废弃掉了1min定时任务触发过期消息发送,采用了java Lock await/singlal方式实现过期消息的实时发送低延时
架构师基于Redis实现延时队列服务
  • 多节点部署结构:

架构师基于Redis实现延时队列服务
– pull job:这里分别为每一个队列创建了一个pull job thread,功能很简单,就是负责去队列中拉取过期的消息数据(这里保证一个队列有且只有一个pull job)
– worker:pull job拉取到的过期消息会交给一个worker thread去处理,这样的好处是处理过期的消息实时性更高(pull job不必等去除过期消息全部处理完成在继续去拉取新的过期数据)
– zookeeper coordinate:通过zk的操作来完成对队列的重新分配工作,daemon thread监听zk节点的创建和删除
  • 主要流程:

服务启动会注册zk,获取分配处理的queues,启动后台线程监听zk 。
为每个分配queue创建一个pull job 。
pull job首先会去queue中查询是否有过期消息:
    Y:将取出消息交给worker处理
     N:查询queue中最后一个成员(zset结构默认按score递增排序),如果为空,则await;不为空则await(成员score-System.currentTimeMillis())
由于过期消息发送成功才会从队列中remove,所以pull job会记录上一次查询队列的一个offset,每次获取到过期消息会将offset向前偏移,过期消息交给worker处理,当worker由于某些异常原因处理失败会重置pull job中offset,这样可以避免消息发送一次失败之后没办法在继续处理(除了新节点add || remove时候)。
当部署服务有新增,延时队列服务会重新计算得到当前处理队列,并将之前创建pull job cancel,为新处理队列重新创建pull job。删除同理。

如喜欢本文,请点击右上角,把文章分享到朋友圈

·END·

    作者:Simple

    来源:www.cnblogs.com/lylife/p/7881950.html

    版权申明:内容来源网络,仅供分享学习,版权归原创者所有。除非无法确认,我们都会标明作者及出处,如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

    架构师指南


    关注公众号,回复关键词:架构师 


    获取2T架构师学习资料


    架构师基于Redis实现延时队列服务

    本篇文章来源于微信公众号:架构师指南

    原创文章,作者:software,如若转载,请注明出处:https://www.sldh123.com/2986.html

    (0)
    上一篇 8月 10, 2022 6:00 上午
    下一篇 8月 11, 2022 1:02 上午

    相关推荐

    • 掌握Git命令的本质,开发时才会得心应手

      点击上方 蓝字 关注我们! 0 前言 作为当前世界上最强大的代码管理工具Git相信大家都很熟悉,但据我所知有很大一批人停留在clone、commit、pull、…

      8月 25, 2022
      450
    • 千万级并发架构下,关系型数据库应该如何优化?

      作者:善思者_tin链接:https://www.jianshu.com/p/c2c081b51ab9 一、概述 顺势而为,大数据高并发要有系统不断的升级,分库分表便是其一。 二、…

      11月 13, 2022
      640
    • 架构师都应该知道的康威定律

      今天的分享主要来自我之前的工作经验以及平时的学习总结和思考。我之前的背景主要是做框架、系统和平台架构,之前的工作过的公司 eBay、携程、唯品会都是平台型互联网公司,所以今天主要带…

      10月 4, 2022
      600
    • 一文弄懂责任链设计模式

      目录 背景 什么是责任链 使用场景 结语 背景 最近,我让团队内一位成员写了一个导入功能。他使用了责任链模式,代码堆的非常多,bug 也多,没有达到我预期的效果。 实际上,针对导入…

      10月 2, 2022
      580
    • 架构师必须了解的微服务和技术栈

      一、简介         这些年软件的设计规模越来越庞大,业务需求也越来越复杂,针对系统的性能、高吞…

      6月 28, 2022
      400
    • 如何管理分布式团队?

      如今,寻找和雇用所有必要的人才来建立你的数字产品是具有挑战性的。因此,许多企业选择替代解决方案,并将其项目的某些部分外包。因此,他们可以扩大专业知识,实现更大的灵活性,提高生产力,…

      8月 15, 2022
      490
    • 架构师透过浏览器看HTTP缓存

      架构师指南 作为前端开发人员,对于我们的站点或应用的缓存机制我们能做的似乎不多,但这些却是与我们关注的性能息息相关的部分,站点没有做任何缓存机制,我们的页面可能会因为资源的下载和渲…

      9月 23, 2022
      550
    • 基于Spring Cloud的微服务架构分析

      Spring Cloud是一个相对比较新的微服务框架,2016年才推出1.0的release版本. 虽然Spring Cloud时间最短, 但是相比Dubbo等RPC框架, Spr…

      7月 18, 2022
      320
    • 架构师如何设计一个工作流引擎 ?

      第1关 一天,老板找到我,说要做个简单的工作流引擎。 我查了一天啥是工作流,然后做出了如下版本: 按顺序添加任意个审批人组成一个链表,最后加一个结束节点 记录当前审批人,当审批完后…

      7月 21, 2022
      500
    • MySQL架构演进:从主从复制到分库分表

      背景 业务飞速发展导致数据规模急速膨胀,单机的数据库已经无法满足互联网业务的发展。 传统的将数据集中存储单一数据结节的方案,在容量、性能、可用性和可维护性方面已经难以满足互联网海量…

      10月 20, 2022
      670

    发表回复

    您的电子邮箱地址不会被公开。