队列本身其实是个有序的列表,而Redis是支持list的,我们可以查看Redis的官方文档 http://redis.io/commands#list,其中我们可以对这个队列的两端分别进行操作,所以其实Redis中的list即可以当做普通的先进先出的queue,也可以作为先进后出的stack。

如果当做队列来用,我们可以用LPUSH(头部插入)和RPOP(尾部弹出)或RPUSH(尾部插入)和LPOP(头部弹出),这两种方式都可以,只要是搭配使用即可。但我们平时一般搭配使用 LPUSH和RPOP。

一般开发的时候我们会分为生产者和消费者,生产者生产消息,消费者获取消息进行处理。

Producer:
redis->lpush(‘joblist’, ‘this is Job-1’);
redis->lpush(‘joblist’, ‘this is Job-2’);
….
Cosumer:
job = redis->rpop(‘joblist’);// return Job-1
done the job….
job = redis->rpop(‘joblist’);// return Job-2
done the job…

正常情况下上面这些都是没问题的,但是我们也经常遇到这种情况,当任务进行到一半(即任务没有完全执行完)的时候,突然服务器宕机或者网络中断,这时候任务其实是没有真正完成的,这时候出现队列中的任务“丢失”了,并不是说队列任务真的丢失了,而是我们把任务从队列拿出来之后并没有完成这个任务,这时候我们就需要考虑如何能在任务真正完成的时候才把任务从队列中删除。

幸运地是,redis其实给我们提供了这样的可能。继续翻看redis的官方文档,我们发现 RPOPLPUSH,从字面含义来解释就是尾部弹出头部插入,它后面跟两个参数,一个是弹出的list,一个是要插入的list,而且文档上告诉我们它可以实现 可靠的队列。我们可以把任务从队列中取出来放到另外一个执行中的队列,等到任务真正完成之后再从执行中的队列中删除。

那么上面的代码我们可以修改成如下,producer不变:

Cosumer:
job = redis->rpoplpush(‘joblist’, ‘job-doing’);// 把Job-1从joblist转移到job-doing
done the job….// 完成Job-1
redis->lrem(‘job-doing’, 1, job);// 等Job-1完成之后把它从job-doing队列中删除

这样如果Job失败,那Job的任务还存在在队列job-doing中,我们可以单独启一个进程来扫描job-doing列表,如果一个job长时间在队列中,则重新执行该Job或重新插入的job列表。

当然,这也不是完全100%靠谱的解决方案,因为如果存在很多相同的job,那我们从job-doing删除job的时候就无法确认是哪个job真正应该删除,但是像我们上面描述的,既然Job是相同的,那我们删除哪个也无所谓了,反正执行的结果都一样。上面的解决方案还有一个问题,我们必须要长时间地监控job-doing列表,这需要额外的资源,还有一种方式是job-doing和job用同一个列表,即:

Cosumer:
job = redis->rpoplpush(‘joblist’, ‘jobllist’); 把Job-1从joblist尾部转移到joblist头部
done the job….// 完成Job-1
redis->lrem(‘job-doing’, 1, job);// 等Job-1完成之后把它从joblist头部删除

其实,文章写到这里,大家应该明白了,这样一来,我们利用循环队列,即可实现可靠的队列。当然,相比较世面上比较成熟的队列,例如 RabbitMQ、 Beanstalkd、 IronMQ等还是有很多的不足,但是如果是简单地项目或者项目本身就已经在使用redis又不想添加新的组件,试试redis list也不错。

用redis做简单的任务队列(一)的更多相关文章

  1. 用redis做简单的任务队列(二)

    是用redis做任务队列时,要思考: 用什么数据类型来做任务队列 怎样才能防止重复爬取 上一篇文章已经决定使用list来做任务队列,但是去重问题没有得到解决.这里可以用set来解决思考二的问题,就是防 ...

  2. 程序员修神之路--redis做分布式锁可能不那么简单

    菜菜哥,复联四上映了,要不要一起去看看? 又想骗我电影票,对不对? 呵呵,想去看了叫我呀 看来你工作不饱和呀 哪有,这两天我刚基于redis写了一个分布式锁,很简单 不管你基于什么做分布式锁,你觉得很 ...

  3. 使用Redis做MyBatis的二级缓存

    使用Redis做MyBatis的二级缓存 通常为了减轻数据库的压力,我们会引入缓存.在Dao查询数据库之前,先去缓存中找是否有要找的数据,如果有则用缓存中的数据即可,就不用查询数据库了. 如果没有才去 ...

  4. redis 的简单命令

    以下实例讲解了如何启动 redis 客户端: 启动 redis 客户端,打开终端并输入命令 redis-cli.该命令会连接本地的 redis 服务. $redis-cli redis > re ...

  5. spring-boot集成mybatis,用redis做缓存

    网上有很多例子了,执行源码起码有3个,都是各种各样的小问题. 现在做了个小demo,实现spring-boot 用redis做缓存的实例,简单记录下思路,分享下源码. 缓存的实现,分担了数据库的压力, ...

  6. 使用Redis做分布式

    一 为什么使用 Redis 在项目中使用 Redis,主要考虑两个角度:性能和并发.如果只是为了分布式锁这些其他功能,还有其他中间件 Zookpeer 等代替,并非一定要使用 Redis. 性能: 如 ...

  7. NetCore入门篇:(九)Net Core项目使用Session及用Redis做分布式

    一.简介 1.因为Net Core默认是没有启动Session功能的,如果需要使用,需要通过代码开启. 2.本篇说明如果启用默认Session实现,即Session存到内存中. 3.本篇扩展说明如何用 ...

  8. Redis的简单了解以及主从复制

    1.Redis的简单了解 Redis是一种高性能的分布式NoSql数据库,持久存储,高并发,数据类型丰富,通过现场申请内存空间,同时可以配置虚拟内存.五种数据类型:string(字符串,这种格式和me ...

  9. Redis主从复制简单介绍

    由于本地环境的使用,所以搭建一个本地的Redis集群,本篇讲解Redis主从复制集群的搭建,使用的平台是Windows,搭建的思路和Linux上基本一致! (精读阅读本篇可能花费您15分钟,略读需5分 ...

随机推荐

  1. SPA (单页应用程序)

    单页Web应用 编辑 单页Web应用(single page web application,SPA),就是只有一张Web页面的应用.单页应用程序 (SPA) 是加载单个HTML 页面并在用户与应用程 ...

  2. 推荐一个SAM文件中flag含义解释工具--转载

    SAM是Sequence Alignment/Map 的缩写.像bwa等软件序列比对结果都会输出这样的文件.samtools网站上有专门的文档介绍SAM文件.具体地址:http://samtools. ...

  3. java 从List中随机取出一个元素

    java 从List中随机取出一个元素 List<Integer> list = new ArrayList<>(); Random random = new Random() ...

  4. python 时间戳转元组

    #!/usr/bin/python # -*- coding: UTF- -*- import time localtime = time.localtime(time.time()) print(& ...

  5. Python day17 模块介绍1(time,random)

    module模块和包的介绍(略掉了) 常用模块 # time模块 import time print(time.time())#时间戳,在1970年开始到现在一共多少秒 print(time.gmti ...

  6. Java8 新特性之默认接口方法

    摘要: 从java8开始,接口不只是一个只能声明方法的地方,我们还可以在声明方法时,给方法一个默认的实现,我们称之为默认接口方法,这样所有实现该接口的子类都可以持有该方法的默认实现. · 待定 一. ...

  7. threejs和3d各种效果的学习

    写给即将开始threejs学习的自己,各种尝试,各种记忆.不要怕,灰色的年华终会过去. 一个技术学习的快慢,以及你的深刻程度,还有你的以后遇到这个东西的时候的反应速度,很大程度上,取决于你的博客的深刻 ...

  8. Windows 2008 更改网卡绑定顺序

    用 ncpa.cpl 或者用鼠标右键点网上邻居进去也好. 来到网卡列表画面. 然后,你会发觉没有菜单去操作[高级设置], 这里,最高级的步骤来了, 就是你需要按一个 [Alt]把菜单给显示出来,太神奇 ...

  9. Java 如何抛出异常、自定义异常、手动或主动抛出异常

    public static void main(String[] args) { try { throw new Exception("抛出异常"); } catch (Excep ...

  10. [转]TOMCAT启动提示NB: JAVA_HOME should point to a JDK not a JRE解决

    来源:http://blog.csdn.net/caozhongyan/article/details/6602759 本人使用的Tomcat版本为apache-tomcat-6.0.18(用的是解压 ...