3.3 Redis实战之任务队列实现

一、概述

在处理Web客户端发送的命令请求时,某些操作的执行时间可能会比我们预期的更长一些。通过将待执行的相关信息放入队列里面,并在之后对队列进行处理,用户可以推迟执行那些需要一段时间才能完成的操作,这种将工作交给任务管理器来执行的做法称为任务队列。

例如:很多网站中都会有发送邮件的这个功能,发送邮件是一个双向数据的交互过程,如果使用单线程实现,很难避免会等待很长时间的情况出现,但碍于某些框架或语言不容易实现多线程,这时可以通过进程来实现。设想一个进程能够完成发邮件的功能,那么只要通知这个进程向指定的地址发送邮件就可以了。这时候,通知的过程可以借助任务队列来实现。
与任务队列交互的类有两种:一类是生产者,另一类是消费者。生产者会将需要的任务放入任务队列中,而消费者则不断从任务队列中读取任务信息并执行。

在这里插入图片描述
在这里插入图片描述
生活中的案例说明:就比如生活中的送快递,快递员送快递在你家门口,刚好你不在家,那就比较浪费快递员的时间,和影响其他快递的配送,造成效率变低。但是如果是通过菜鸟驿站的话,就实现了快递员和你之间的解耦,快递员直接将快递放在驿站,你什么时候有空就去拿快递,效率就会大大的提高了。

二、Redis实现任务队列

1.任务队列

松耦合性
生产者和消费者无需知道彼此的实现细节,只需要约定好任务的秒速格式,这使得生产者和消费者可以由不同的团队使用不同的编程语言编写。
(就好比刚刚觉得生活中的例子,快递员他不需要知道要签收人是谁,他只需要将快递放在菜鸟驿站即可,而签收人也不需要知道快递员是谁和了解是什么快递这些细节,他只需要去菜鸟驿站取就可以了)

易于拓展
消费者可以有多个,而且可以分布在不同的服务器中,如下图,借此可以轻易的降低单台服务器的负载。
在这里插入图片描述

2.任务队列的实现

Redis中实现任务队列我们可以通过List中的LPUSH和RPOP命令来实现。如下:

while(true){
	String task=rpop("queue");
	if(task != null){
		execute(task);
	}else{
		//如果没有则等待1秒钟,防止过于频繁的请求数据
		Thread.sleep(1000);
	)
}

上面的代码实现了一个简单的任务队列,但是不够完善,因为当任务队列中没有任务时消费者每秒都会调用RPOP命令去查看是否有新任务,我们想要实现的是:如果有新的任务添加进来我们能够立马知道,这是可以使用BRPOP命令来实现。
BRPOP命令的作用和RPOP作用是一样的,都是将List中最右侧弹出并返回,唯一不同的是BRPOP是阻塞的,如果没有元素会一直等待到新加元素或者超时。

//无限循环读取任务队列中的内容
while(true){
	//BRPOP命令接受两个参数:第一个是key,第二个是超出时间,单位是秒
	String task=brpop("queue",0);
	//执行任务
	execute(task);
}

2.1 实现步骤

BRPOP命令接受两个参数:第一个是key,第二个是超出时间,单位是秒
在Redis一个实例中

127.0.0.1:6379> brpop queue 0

这时会进入等待状态
在这里插入图片描述
在另外一个实例中执行命令

127.0.0.1:6379> lpush queue task2 [

在这里插入图片描述
这时阻塞的实例立即获取到结果

在这里插入图片描述

3.优先级队列

实际环境中我们可能需要监听多个任务队列,有些队列的优先级比较高,需要优先执行,这种情况还是使用BRPOP命令来实现。
BRPOP命令可以同时接受多个键,其语法格式为BRPOP key[key…] timeout,brpop queue1 queue2 0,表示同时检测多个键,如果所有键中都没有元素则阻塞。
如果其中有一个键有元素则会从该键中弹出元素。

A实例中:

127.0.0.1:6379> brpop queue1 queue2 0

这时候阻塞

B实例中:

127.0.0.1:6379> lpush queue1 task task2 task3
(integer) 3
127.0.0.1:6379> lpush queue2 zhang li liu
(integer) 3

则A中按优先级。
如果多个键都有元素则按照从左到右的顺序取第一个键的元素,这条是实现优先级队列的关键

127.0.0.1:6379> brpop queue1 queue2 0
1) "queue1"
2) "task"
127.0.0.1:6379> brpop queue1 queue2 0
1) "queue1"
2) "task2"
127.0.0.1:6379> brpop queue1 queue2 0
1) "queue1"
2) "task3"
127.0.0.1:6379> brpop queue1 queue2 0
1) "queue2"
2) "zhang"
127.0.0.1:6379> brpop queue1 queue2 0
1) "queue2"
2) "li"
127.0.0.1:6379> brpop queue1 queue2 0
1) "queue2"
2) "liu"
127.0.0.1:6379> brpop queue1 queue2 0

根据BRPOP这个特性我们就可以实现任务队列的优先级了。我们分别使用queue:confirmation.email和queue:notification.email两个键存储发送确认邮件和发送通知邮件两个任务,实现代码如下:

while(true){
	String task=brpop("queue:confirmation.email","queue;notification.email",0);
	execute(task);
}

这时一旦发送了确认邮件的任务被加入到queue:confirmation.email队列中,无论queue;notification.email还有多少任务,消费者都会有限完成发送确认邮件的任务。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值