写在前面:Redis的消息队列并不是专业的消息队列,没有ACK保证,没有特别多的高级特性,如果对消息的可靠性有很高的要求,就放弃它吧。

1.Redis消息队列

Redis通过内部的list数据结构来实现异步消息队列。通过`rpush`和`lpop`操作结合构成类似队列(先进先出)的效果;也可以通过`rpush`与`rpop`构成堆栈(后进先出)的效果。但一般消息队列都采用队列效果的组合形式。

>rpush hobby basketball football tennis
(integer) 3
>lpop hobby
"basketball" >lpop hobby
"football" >lpop tennis
"tennis" >lpop hobby
(nil)

客户端通过队列的pop操作获取消息,然后进行处理,处理完了再接着获取消息,然后再处理,一直循环,这就是队列消费者客户端的生命周期。

如上所述,假如队列空了,pop操作拿不到数据,客户端因此陷入一直pop的死循环产生一堆无用的空轮询,同时消耗着客户端和Redis服务端的资源,怎么办?

首先能想到的方法可能会是让队列为空的请求,通过sleep命令让线程停下来。更好的做法是通过blpopbrpop代替之前的lpoprpop,即用阻塞读(在队列没有数据时,立即进入休眠状态;当数据到来,立刻重新请求)的方式,解决因为sleep命令带来的延迟。

但这样就会有新的问题产生:当列表长时间没有数据时,客户端线程会一直被阻塞,形成闲置连接,而这种情况下,服务器为了节省资源通常会断开这条链接。客户端的blpop/brpop就会报错。

所以编写客户端消费者时要捕获异常,进行重试。

2.延时队列

延时队列的出现是为了解决在分布式开发中,客户端在处理请求时加锁失败的问题。这种方式是将当前冲突的请求扔进另一个队列延后处理以避开锁的冲突。

在Redis中延时队列的实现是由zset(有序列表)来实现,基本使用方式为zset key score value。在延时队列中常常把消息序列化成一个字符串作为 zsetvalue,消息的过期时间作为score,然后用多个线程(保证可用性)来轮询zset来获取到期的任务进行处理。考虑到并发抢任务,任务就有可能被多次执行。

def delay(msg):
msg.id = str(uuid4()) #序列化保证value的唯一性
value = json.dumps(msg)
retry_ts = time.time() + 5 # 5s后重试
redis.zadd('delay-queue',retry_ts,value) def loop():
while True:
# 最多取一条
value_list = redis.zrangebyscore("delay-queue",0,time.time(),start=0,num=1):
if not value_list:
time.sleep(1)
continue
value = value_list[0]
# 将取到的消息从redis消息队列中删除
success = redis.zrem("delay-queue",value)
# 多进程并发下,只有一个线程可以抢到消息
if success:
msg = json.loads(value)
handle_msg(msg)

Redis中的`zrem`方法是保证多线程争抢任务不发生混乱的关键。
需要注意的是在执行*handle_msg()* 时一定要进行异常捕获,避免因单个任务出现问题导致循环异常退出。

Redis学习笔记02-消息队列与延时队列的更多相关文章

  1. Redis学习笔记~实现消息队列比MSMQ更方便

    什么是队列:简单的说就是数据存储到一个空间里(可以是内存,也可以是物理文件),先存储的数据对象,先被取出来,这与堆栈正好相反,消息队列也是这样,将可能出现高并发的数据进行队列存储,并按着入队的顺序依次 ...

  2. redis学习笔记-02:为什么使用NoSQL数据库

    一.第一代:单机版的MySQL 1.静态网页,动态交互类型的网站不多. 2.架构:APP---->DAL---->MySQL Instance 3.数据存储的瓶颈: (1)数据量总大小超过 ...

  3. redis学习笔记-02 list列表类型命令

    一.lpush key value1 value2 value3 value4(命令将一个或多个值插入到列表头部. 如果 key 不存在,一个空列表会被创建并执行 LPUSH 操作) lpush k1 ...

  4. Redis学习笔记~目录

    回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...

  5. Redis:学习笔记-02

    Redis:学习笔记-02 该部分内容,参考了 bilibili 上讲解 Redis 中,观看数最多的课程 Redis最新超详细版教程通俗易懂,来自 UP主 遇见狂神说 4. 事物 Redis 事务本 ...

  6. Linux进程间通信IPC学习笔记之消息队列(SVR4)

    Linux进程间通信IPC学习笔记之消息队列(SVR4)

  7. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  8. Redis学习笔记4-Redis配置具体解释

    在Redis中直接启动redis-server服务时, 採用的是默认的配置文件.採用redis-server   xxx.conf 这种方式能够依照指定的配置文件来执行Redis服务. 依照本Redi ...

  9. Redis学习笔记八:集群模式

    作者:Grey 原文地址:Redis学习笔记八:集群模式 前面提到的Redis学习笔记七:主从复制和哨兵只能解决Redis的单点压力大和单点故障问题,接下来要讲的Redis Cluster模式,主要是 ...

  10. redis学习笔记(详细)——高级篇

    redis学习笔记(详细)--初级篇 redis学习笔记(详细)--高级篇 redis配置文件介绍 linux环境下配置大于编程 redis 的配置文件位于 Redis 安装目录下,文件名为 redi ...

随机推荐

  1. JS switch 分支语句

    描述:根据一个变量的不同取值,来执行不同的代码. 语法结构: switch(变量) { case 值1: 代码1; break; case 值2: 代码2; break; case 值3: 代码3; ...

  2. QString组合、拆分。

    1.组合字符常用arg()函数 QString test=QString("_haha_%1_hehe%2") .arg("ee").arg("aa& ...

  3. 17.splash_case01

    # 抓取今日头条,对比渲染和没有渲染的效果 import requests from lxml import etree # url = 'http://localhost:8050/render.h ...

  4. Java编译与反编译命令记录

    1.首先进入java文件所在的地址 1) e:/ 2) dir     (显示所有文件) 3) cd eclipse-workspace 2.使用javac命令编译Test.java文件,得到Test ...

  5. Go前言

    Go语言为并发而生 硬件制造商正在为处理器添加越来越多的内核以来提高性能.所有数据中心都在这些处理器上运行,今天的应用程序使用多个微服务来维护数据库连接,消息队列和维护缓存.所以,开发的软件和编程语言 ...

  6. software database is broken解决办法

    ubuntu切换中文时报software database is broken错误. 网上的办法千篇一律,还都没有用.都是去应用中心删除thundbird之类的,啊....... 在终端下执行 sud ...

  7. spring自定义bean工厂模式解耦

    在resources下创建bean.properties accountService=cn.flypig666.service.impl.AccountServiceImpl accountDao= ...

  8. csp-s模拟测试56Merchant, Equation,Rectangle题解

    题面:https://www.cnblogs.com/Juve/articles/11619002.html merchant: 二分答案,贪心选前m大的 但是用sort复杂度不优,会T掉 我们只是找 ...

  9. Python-函数基础(2)

    目录 可变长参数 形参 实参 函数对象 函数嵌套 名称空间与作用域 名称空间 内置名称空间 局部名称空间 全局名称空间 执行顺序 搜索顺序 作用域 全局作用域 局部作用域 global nonloca ...

  10. 面向对象_访问修饰符_构造与析构函数_this指针

    1:面向对象 以codeblocks举例,在一个工程里面: File-->new -->Class可以建一个类,可以设置类的参数,是否有set get方法,有无构造函数等设置,.h文件主要 ...