三、Redis做延时队列

本文介绍了使用Redis作为简单消息队列的场景,强调在低需求时的适用性。讨论了Redis列表作为异步消息队列的操作,并提出阻塞读取以避免空循环导致的资源浪费,利用blpop/lrpop命令实现阻塞读。接着,文章阐述了如何利用Redis的有序集合(zset)来创建延时队列,通过设置score为到期时间戳来管理到期任务。

前言

      现在市面上有很多好用的开源的消息队列中间件,例如RocketMq、Kafka以及Rabbitmq等等,它们都可以在应用程序之间增加异步消息传递功能。但是要使用这些中间件都包含很多组件,在你的消费队列很少的情况下就显得不是很好。
      Redis做队列就可以处理这种甚至只有一组消费者的消费队列。当然要注意的是,Redis的消息队列不是专业的消息队列,没有那么多的高级特性,没有ack保证,如果对消息的可靠性有着极高的要求,那么它就不适合使用。

1、异步消息队列

      Redis的list(列表)数据结构是常用来作为异步的消息队列使用,使用rpush和lpush操作入队,用lpop和rpop命令操作出队,如图所示:

在这里插入图片描述
      它可以支持多个生产者和多个消费者并发进出消息,每个消费者拿到的消息都是不同的元素,如果所示:
在这里插入图片描述
      下面是rpush和lpop结合使用的例子。lpush和rpop同理。
在这里插入图片描述

2、队列之阻塞读

      消费端通过队列的pop操作来获取消息,然后进行相应的业务处理。然后再循环的获取消息。这就是作为队列消费者的客户端的生命周期。
      但是如果队列空了的话,消费端就会陷入pop的死循环,这样既会增加机器的CPU消耗,Redis的QPS也会同步提升,这样显然是不合理的。
      最简单的办法就是让消费线程sleep一会,这样是可以解决上述的问题,但是会增加消费端的延迟。Redis为我们提供了相应的阻塞pop操作,对应的命令是blpop/lrpop。这两个命令的前缀b代表的是blocking,也就是阻塞。阻塞读在队列没有数据的时候,会立即进入休眠状态,一但数据到来,则立即唤醒。消息的延迟几乎为0。这样就可以完美解决队列为空的场景。
      但是这种使用还会存在一个问题,就是空闲连接的问题。如果线程一直阻塞在哪里,Redis的客户端连接就成了闲置连接,当闲置时间过长的时候,服务器会主动断开连接,减少资源占用。这是blpop/brpop会抛出异常,所以要特别注意。

3、延时队列的实现

      延时队列可以通过Redis的zset(有序集合)来实现。我们把具体的消息数据序列化成字符串作为一个value,将消息到期处理时间的时间戳作为score,然后启动线程去轮训zset获取到期的任务进行处理。

# coding:utf-8
import uuid
import json
import time
import redis

delay_queue_key = 'delay-queue'

def delay(client, msg):
	msg['id'] = str(uuid.uuid4())
	value = json.dumps(msg)
	retry_ts = time.time() + 5
	#新版redis模块传参是一个dict,key是要存储的val,value为score
	client.zadd(delay_queue_key, {value: retry_ts})

def loop(client):
	while True:
		#每次拉去一条
		values = client.zrangebyscore(delay_queue_key, 0, time.time(), start=0, num=1)
		if not values:
			#m没有数据 sleep
			time.sleep(1)
			continue
		value = values[0]
		#如果多线程消费  存在并发  只有一个线程可以抢到该消息
		success = client.zrem(delay_queue_key, value)
		if success:
			msg = json.loads(value)
			print("consume msg : ", msg)

#连接redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
client = redis.Redis(connection_pool=pool)
#清空数据库
client.flushall()

msg_body = {'name':'llq', 'age':36}

delay(client, msg_body)
loop(client)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值