咳咳咳,大家不要误会,本文很正经的啦!
好了,接下来回到我们的话题,我们都知道Redis是一种基于内存的单进程单线程数据库(Redis6.0开始之后支持多线程啦!
),处理速率都非常快。那么为何Redis又能慢呢?原来,这里说的慢是指Redis可以设置一些参数达到慢处理的结果。(这便是为什么Redis既能快又能慢啦!
)
那接下来开始讲讲我们的模范Redis在行列步队中如何实现延时的情形:

在我们日常生活中,我们可以创造,
在淘宝、京东等购物平台高下单,超过一定韶光未付款,订单会自动取消。打车的时候,在规定韶光没有车主接单,平台会取消你的单并提醒你暂时没有车主接单。点外卖的时候,如果商家在10分钟还没接单,就会自动取消订单。收快递的时候,如果我们没有点确认收货,在一段韶光后程序会自动完成订单。在平台完成订单后,如果我们没有在规定韶光评论商品,会自动默认买家不评论。.......还有很多这样的场景。这时,我们可以想想为什么要这样做?
由于这样可以担保商品的库存可以开释给其他人购买,你可以不用一贯等待打车却得不到回答,你可以及时换一家店点到外卖。
那么这些情形都是如何实现的呢?
这时我们可以看看这个图,来看看延迟是如何处理的:
当用户发送一个要求给做事器后台的时候,做事器会检测这条是否须要进行延时处理,如果须要就放入到延时行列步队中,由延时任务检测器进行检测和处理,对付不须要进行延时处理的任务,做事器会立马对进行处理,并把处理后的结果相应返会给用户。
对付在延时任务检测器内部的话,有查询延迟任务和实行延时任务两个职能,任务检测器会先去延时任务行列步队进行行列步队中信息读取,判断当前行列步队中哪些任务已经韶光到期并将已经到期的任务输出实行(具有实时性,会存在一定的韶光偏差,由于这个是定时任务)。
这时,我们可以想一想在Redis的数据构造中有哪些能进行韶光设置标志的命令?
是不是想到的 zset 这个命令,具有去重有序(分数排序)的功能。没错,你想对了呀!
我们可以利用 zset(sortedset)这个命令,用设置好的韶光戳作为score进行排序,利用 zadd score1 value1 ....命令就可以一贯往内存中生产。再利用 zrangebysocre 查询符合条件的所有待处理的任务,通过循环实行行列步队任务即可。也可以通过 zrangebyscore key min max withscores limit 0 1 查询最早的一条任务,来进行消费。
总的来说,你可以通过以下两种办法来实现((^▽^)如果你想到其他方法,也可以见告我下呀~):
利用zrangebyscore来查询当前延时行列步队中所有任务,找出所有须要进行处理的延时任务,在依次进行操作。查找当前最早的一条任务,通过score值来判断任务实行的时候是否大于了当前系统的时候,比如说:最早的任务实行韶光在3点,系统韶光在2点58分),表示这个该当须要立马被实行啦,韶光快到了(冲冲冲,他来了他来了,他带着去世神的步伐来了)。我们可以想一想Redis来实现延时行列步队有何上风呢?
实在,Redis用来进行实现延时行列步队是具有这些上风的:
Redis zset支持高性能的 score 排序。Redis是在内存上进行操作的,速率非常快。Redis可以搭建集群,当很多时候,我们可以用集群来提高处理的速率,提高可用性。Redis具有持久化机制,当涌现故障的时候,可以通过AOF和RDB办法来对数据进行规复,担保了数据的可靠性这时候,会有小伙伴问了还有没有其他实现延时行列步队的办法呀!
emmm....当然有的,只有想不到的没有做不到(O(∩_∩)O哈哈~,开玩笑)
(1)通过 RabbitMQ 来实现延时行列步队,也便是用中间件来实现延时行列步队啦~
方法一:在MQ中我们可以对Queue设置 x-expires 过期韶光或者对 Message设置超时时间x-message-ttl。
(这里要把稳下:延时相同的我们要扔到同一个行列步队中,对付每一个延时要建立一个与之对应的行列步队—这是由于MQ的过期检测是惰性检测的。)
方法二:我们可以用RabbitMQ的插件rabbitmq-delayed-message-exchange插件来实现延时行列步队。达到可投递韶光时并将其通过x-delayed-type类型标记的交流机类型投递至目标行列步队。
(2)RocketMQ实现延时行列步队
rocketmq在发送延不时,是先把按照延迟韶光段发送到指定的行列步队中(把延时时间段相同的放到同一个行列步队中,担保了处理的顺序性,可以让同一个行列步队中延时时间是相同的,全体RocketMQ中延不时按照递增顺序排序,担保信息处理的先后顺序性。)。之后,通过一个定时器来轮询处理这些行列步队里的信息,判断是否到期。对付到期的会发送到相应的处理行列步队中,进行处理。
哈哈,目前RocketMQ只支持特定的延时时间段,1s,5s,10s,...2h,不能支持任意韶光段的延时设置。有兴趣的小伙伴可以去理解下它是干系知识呀~
二、Kafka实现延时队
Kafka基于韶光轮自定义了一个用于实现延迟功能的定时器(SystemTimer),Kafka中的韶光轮(TimingWheel)是一个存储定时任务的环形行列步队,可以进行干系的延时行列步队设置。
三、Netty实现延时行列步队
Netty也有基于韶光轮算法来实现延时行列步队。Netty在构建延时行列步队紧张用HashedWheelTimer,HashedWheelTimer底层数据构造是利用DelayedQueue,采取韶光轮的算法来实现。
四、DelayQueue来实现延时行列步队
Java中有自带的DelayQueue数据类型,我们可以用这个来实现延时行列步队。DelayQueue是封装了一个PriorityQueue(优先行列步队),在向DelayQueue行列步队中添加元素时,会给元素一个Delay(延迟韶光)作为排序条件,行列步队中最小的元素会优先放在队首,对付行列步队中的元素只有到了Delay韶光才许可从行列步队中取出。这种实现办法是数据保存在内存中,可能面临数据丢失的情形,同时它是无法支持分布式系统的。