0

0

浅析Redis中怎么使用消息队列

青灯夜游

青灯夜游

发布时间:2022-01-05 09:57:35

|

3058人浏览过

|

来源于掘金社区

转载

本篇文章带大家了解一下redis进阶用法-消息队列,介绍一下redis中的延时队列,希望对大家有所帮助!

浅析Redis中怎么使用消息队列

说到消息队列中间件,我们都会想到RabbitMQ、RocketMQ和Kafka,来给应用实现异步消息传递的功能。这些都是专业的消息队列中间件,其特性之多超出了我们的理解能力。

而这些消息中间件使用起来的是复杂的,例如RabbitMQ,发消息之前要创建Exchange,还要创建Queue,然后将Exchange和Queue通过某种规则绑定起来,发送消息的时候还要制定routing-key,还要 控制头消息。这仅是生产者,消费者在消费消息之前也要将上面一系列的繁琐步骤再操作一遍。

那么对于那些并不要求百分百可靠,并且希望实现简单的消息队列需求时,我们可以通过Redis将我们从消息队列的中间件的繁琐步骤中解脱出来。

Redis的消息队列不是专业的消息队列,他并没有消息队列中许多的高级特性,也没有ack保证。如果对消息的可靠性有着极致的追求,请转向专业的MQ中间件。【相关推荐:Redis视频教程

异步消息队列

从最简单的异步消息队列开始,Redis的list数据结构常用来作为异步消息队列,通过lrpush/lpush来操作入列,通过rpop/lpop来出列。

1.png

问题一:空队列

对于pop操作来说,当消息队列空了的时候,客户端会陷入pop的死循环,造成大量的浪费生命的空轮询,导致客户端CPU拉高,同时Redis的QPS也被拉高。

对于以上问题的解决办法就是通过list结构的blpop/brpop来操作出列,其中b前缀代表的就是blocking,阻塞读。对于阻塞读在队列没有数据的时候就会进入休眠状态,一旦数据到来就会立刻醒来。完美的解决了上面这个问题。

问题二:空闲连接断开

阻塞读的方案看似完美,紧接着引出了另外一个问题:空闲连接。 如果线程一直阻塞在哪哪里,Redis的客户端连接就变成了空闲连接。空闲时间过长,Redis服务器就会主动断开连接,以减少闲置资源占用。这时候blpop/brpop就会抛出异常来。

Civitai
Civitai

AI艺术分享平台!海量SD资源和开源模型。

下载

所以,我们在编写客户端(应用程序)消费者的时候需要小心,注意捕获异常,并进行重试。

应用一:延时队列

在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一同挪到服务器进行原子操作,就能够完美解决了。

更多编程相关知识,请访问:编程入门!!

相关专题

更多
rabbitmq和kafka有什么区别
rabbitmq和kafka有什么区别

rabbitmq和kafka的区别:1、语言与平台;2、消息传递模型;3、可靠性;4、性能与吞吐量;5、集群与负载均衡;6、消费模型;7、用途与场景;8、社区与生态系统;9、监控与管理;10、其他特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

199

2024.02.23

什么是分布式
什么是分布式

分布式是一种计算和数据处理的方式,将计算任务或数据分散到多个计算机或节点中进行处理。本专题为大家提供分布式相关的文章、下载、课程内容,供大家免费下载体验。

319

2023.08.11

分布式和微服务的区别
分布式和微服务的区别

分布式和微服务的区别在定义和概念、设计思想、粒度和复杂性、服务边界和自治性、技术栈和部署方式等。本专题为大家提供分布式和微服务相关的文章、下载、课程内容,供大家免费下载体验。

229

2023.10.07

什么是中间件
什么是中间件

中间件是一种软件组件,充当不兼容组件之间的桥梁,提供额外服务,例如集成异构系统、提供常用服务、提高应用程序性能,以及简化应用程序开发。想了解更多中间件的相关内容,可以阅读本专题下面的文章。

175

2024.05.11

Golang 中间件开发与微服务架构
Golang 中间件开发与微服务架构

本专题系统讲解 Golang 在微服务架构中的中间件开发,包括日志处理、限流与熔断、认证与授权、服务监控、API 网关设计等常见中间件功能的实现。通过实战项目,帮助开发者理解如何使用 Go 编写高效、可扩展的中间件组件,并在微服务环境中进行灵活部署与管理。

212

2025.12.18

kafka消费者组有什么作用
kafka消费者组有什么作用

kafka消费者组的作用:1、负载均衡;2、容错性;3、广播模式;4、灵活性;5、自动故障转移和领导者选举;6、动态扩展性;7、顺序保证;8、数据压缩;9、事务性支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

166

2024.01.12

kafka消费组的作用是什么
kafka消费组的作用是什么

kafka消费组的作用:1、负载均衡;2、容错性;3、灵活性;4、高可用性;5、扩展性;6、顺序保证;7、数据压缩;8、事务性支持。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

149

2024.02.23

rabbitmq和kafka有什么区别
rabbitmq和kafka有什么区别

rabbitmq和kafka的区别:1、语言与平台;2、消息传递模型;3、可靠性;4、性能与吞吐量;5、集群与负载均衡;6、消费模型;7、用途与场景;8、社区与生态系统;9、监控与管理;10、其他特性。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

199

2024.02.23

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号