浅析Redis中怎么使用消息队列
本篇文章带大家了解一下Redis进阶用法-消息队列,介绍一下Redis中的延时队列,希望对大家有所帮助!
说到消息队列中间件,我们都会想到RabbitMQ、RocketMQ和Kafka,来给应用实现异步消息传递的功能。这些都是专业的消息队列中间件,其特性之多超出了我们的理解能力。
而这些消息中间件使用起来的是复杂的,例如RabbitMQ,发消息之前要创建Exchange,还要创建Queue,然后将Exchange和Queue通过某种规则绑定起来,发送消息的时候还要制定routing-key,还要 控制头消息。这仅是生产者,消费者在消费消息之前也要将上面一系列的繁琐步骤再操作一遍。
那么对于那些并不要求百分百可靠,并且希望实现简单的消息队列需求时,我们可以通过Redis将我们从消息队列的中间件的繁琐步骤中解脱出来。
Redis的消息队列不是专业的消息队列,他并没有消息队列中许多的高级特性,也没有ack保证。如果对消息的可靠性有着极致的追求,请转向专业的MQ中间件。【相关推荐:Redis视频教程】
异步消息队列
从最简单的异步消息队列开始,Redis的list数据结构常用来作为异步消息队列,通过lrpush/lpush来操作入列,通过rpop/lpop来出列。
问题一:空队列
对于pop操作来说,当消息队列空了的时候,客户端会陷入pop的死循环,造成大量的浪费生命的空轮询,导致客户端CPU拉高,同时Redis的QPS也被拉高。
对于以上问题的解决办法就是通过list结构的blpop/brpop来操作出列,其中b前缀代表的就是blocking,阻塞读。对于阻塞读在队列没有数据的时候就会进入休眠状态,一旦数据到来就会立刻醒来。完美的解决了上面这个问题。
问题二:空闲连接断开
阻塞读的方案看似完美,紧接着引出了另外一个问题:空闲连接。 如果线程一直阻塞在哪哪里,Redis的客户端连接就变成了空闲连接。空闲时间过长,Redis服务器就会主动断开连接,以减少闲置资源占用。这时候blpop/brpop就会抛出异常来。
所以,我们在编写客户端(应用程序)消费者的时候需要小心,注意捕获异常,并进行重试。
应用一:延时队列
在Redis的分布式锁中一般有三种策略来处理加锁失败的情况:
直接抛出异常,前端提醒用户是否要继续操作;
sleep一会再重试;
将请求放到延时队列中,一会再重试;
而Redis中延时队列,我们可以通过zset(有序列表)数据结构来实现。我们将消息序列化作为一个字符串作为zse的value,而消息的到期处理时间(延时时间)作为score。然后通过轮询zset获取到期时间进行处理,通过zrem将key从zset移除代表成功消费,进而处理任务。
核心代码如下:
// 生产\ public void delay(T msg) {\ TaskItem task = new TaskItem();\ task.id = UUID.randomUUID().toString(); // 分配唯一的 uuid\ task.msg = msg;\ String s = JSON.toJSONString(task); // fastjson 序列化\ jedis.zadd(queueKey, System.currentTimeMillis() + 5000, s); // 塞入延时队列 ,5s 后再试\ }\ // 消费\ public void loop() {\ while (!Thread.interrupted()) {\ // zrangeByScore参数中0, System.currentTimeMills()代表从redis中去score范围在0到系统当前时间的数据, 0,1表示从0开始取1个 拓展传入的score为-inf, +inf 分别表示zset中的最大值和最小值,当你不知道zset中的score最值时就可以使用inf作为参数变量\ Set values = jedis.zrangeByScore(queueKey, 0, System.currentTimeMillis(), 0, 1);\ if (values.isEmpty()) {\ try {\ Thread.sleep(500); // 歇会继续\ }\ catch (InterruptedException e) {\ break;\ }\ continue;\ }\ String s = values.iterator().next(); //消费队列\ if (jedis.zrem(queueKey, s) > 0) { // 抢到了,要考虑到多线程下锁争抢的情况,只有rem成功代表成功的消费了一条消息。\ TaskItem task = JSON.parseObject(s, TaskType); // fastjson 反序列化\ this.handleMsg(task.msg);\ }\ }\ }
以上的代码在多线程中对于同一个任务被多个线程争抢的情况,虽然能够通过zrem后在处理任务来避免一个任务被多次消费的情况。但是对于那些获取到了任务但是没有成功消费的线程来说,都是白白浪费时间取了一次任务。所以可以考虑通过lua scripting来优化这个逻辑。将zrangeByScore和zrem一同挪到服务器进行原子操作,就能够完美解决了。
更多编程相关知识,请访问:编程入门!!
以上是浅析Redis中怎么使用消息队列的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Redis集群模式通过分片将Redis实例部署到多个服务器,提高可扩展性和可用性。搭建步骤如下:创建奇数个Redis实例,端口不同;创建3个sentinel实例,监控Redis实例并进行故障转移;配置sentinel配置文件,添加监控Redis实例信息和故障转移设置;配置Redis实例配置文件,启用集群模式并指定集群信息文件路径;创建nodes.conf文件,包含各Redis实例的信息;启动集群,执行create命令创建集群并指定副本数量;登录集群执行CLUSTER INFO命令验证集群状态;使

使用 Redis 指令需要以下步骤:打开 Redis 客户端。输入指令(动词 键 值)。提供所需参数(因指令而异)。按 Enter 执行指令。Redis 返回响应,指示操作结果(通常为 OK 或 -ERR)。

理解 Redis 源码的最佳方法是逐步进行:熟悉 Redis 基础知识。选择一个特定的模块或功能作为起点。从模块或功能的入口点开始,逐行查看代码。通过函数调用链查看代码。熟悉 Redis 使用的底层数据结构。识别 Redis 使用的算法。

如何清空 Redis 数据:使用 FLUSHALL 命令清除所有键值。使用 FLUSHDB 命令清除当前选定数据库的键值。使用 SELECT 切换数据库,再使用 FLUSHDB 清除多个数据库。使用 DEL 命令删除特定键。使用 redis-cli 工具清空数据。

Redis 使用单线程架构,以提供高性能、简单性和一致性。它利用 I/O 多路复用、事件循环、非阻塞 I/O 和共享内存来提高并发性,但同时存在并发性受限、单点故障和不适合写密集型工作负载的局限性。

要从 Redis 读取队列,需要获取队列名称、使用 LPOP 命令读取元素,并处理空队列。具体步骤如下:获取队列名称:以 "queue:" 前缀命名,如 "queue:my-queue"。使用 LPOP 命令:从队列头部弹出元素并返回其值,如 LPOP queue:my-queue。处理空队列:如果队列为空,LPOP 返回 nil,可先检查队列是否存在再读取元素。

要查看 Redis 中的所有键,共有三种方法:使用 KEYS 命令返回所有匹配指定模式的键;使用 SCAN 命令迭代键并返回一组键;使用 INFO 命令获取键的总数。

启动 Redis 服务器的步骤包括:根据操作系统安装 Redis。通过 redis-server(Linux/macOS)或 redis-server.exe(Windows)启动 Redis 服务。使用 redis-cli ping(Linux/macOS)或 redis-cli.exe ping(Windows)命令检查服务状态。使用 Redis 客户端,如 redis-cli、Python 或 Node.js,访问服务器。
