Redis做消息队列,香吗?
来自:架构师修行之路
菜菜哥,我刚做完了一个订单系统,感觉很简单呀
说说看,大量的订单状态怎么处理的?
我设计的时候可是考虑了这一点,所以用了异步处理,采用了MQ
那用的什么MQ呢,透露一下呗
我用的redis做的MQ,很简单,一天就写完了
订单那么重要的消息,我觉得用redis可能不适合哦!!
Redis消息队列
在程序员这个圈子打拼了太多年,见过太多的程序员使用redis,其中一部分喜欢把redis做缓存(cache)使用,其中最典型的当属存储用户session,除此之外,把redis作为消息队列使用也不在少数,可见redis在互联网中应用是多么的广泛。
redis作为消息队列使用,redis支持的数据结构是可以支撑这类业务,主要是利用了list这种数据结构的特性。Redis的列表相当于编程语言里面的 LinkedList,是一个双向的列表结构,这意味着列表新增和删除元素是非常快的,时间复杂度为O(1),但是查找一个元素的时候需要遍历列表,时间复杂度为O(n)。由于列表的元素操作和消息队列操作类似,所以redis可以适用于消息队列的场景,当然,在适用于的栈的场景下也可以胜任。
需要提醒一下,生产环境中如果对消息的可靠性有十分高的要求(比如订单支付的消费消息),请使用专业的消息队列(例如:rmq,amq等),对消息的丢失有一定容忍度的程序完全可以使用redis,例如我们的日志收集程序
列表这种数据结构的命令为
移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BLPOP key1 [key2 ] timeout
移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOP key1 [key2 ] timeout
从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它;如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOPLPUSH source destination timeout
通过索引获取列表中的元素
LINDEX key index
在列表的元素前或者后插入元素
LINSERT key BEFORE|AFTER pivot value
获取列表长度
LLEN key
移出并获取列表的第一个元素
LPOP key
将一个或多个值插入到列表头部
LPUSH key value1 [value2]
将一个值插入到已存在的列表头部
LPUSHX key value
获取列表指定范围内的元素
LRANGE key start stop
移除列表元素
LREM key count value
通过索引设置列表元素的值
LSET key index value
对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
LTRIM key start stop
移除列表的最后一个元素,返回值为移除的元素。
RPOP key
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
RPOPLPUSH source destination
在列表中添加一个或多个值
RPUSH key value1 [value2]
为已存在的列表添加值
RPUSHX key value
缺陷
消息队列的本质还是消费者和生产者的问题,只要是这样的场景,就会涉及到两端不平衡的情况,具体可表现为:
1. 生产者生产速度大于消费者消费速度,面临消息不断堆积的问题,随着消息数据的堆积,队列是开启限流措施,还是丢弃某些消息,更或者是把消息数据进行持久化。对于基于redis实现的消息队列,一般为可忍受部分消息丢失的业务,所以很多人选择丢弃消息的方案。另一种方案是基于redis单线程机制,可以增加消费者数量,这也是仅仅针对消息只被消费一次的场景。当然也可以选择持久化方案,但是会对redis的性能产生影响。
2. 消费者消费速度大于生产者生产速度,有的同学会说,这样挺好啊,是,在某种意义上是比反过来的那个场景要好一些,毕竟可以避免产生消息的堆积问题。但是消费者没有消息消费,会导致消费者进程一直在那里浪费cpu资源,而且还会把redis的QPS拉高。类似于这种死循环的场景,一般而且最常用的解决方案是让线程sleep 一小段时间,既降低了消费端cpu也降低了redis的QPS。但是sleep会有一个问题,会导致处理消息的延迟,例如sleep了一秒,那消息的延迟处理就有可能会延迟一秒,虽然在大部分场景下这都不是什么问题,但是作为程序员怎么能不追求极致和完美呢?
关于消息延迟的问题,最暴力简单的方式就是增加消费客户端,这样可用多消费端交错的方式来缩小延迟的间隔,当然redis的设计者也考虑了这个问题,所有有了Blpop 命令
Redis Blpop 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
redis 127.0.0.1:6379> BLPOP LIST1 LIST2 .. LISTN TIMEOUT
而且还可以设置超时自动返回,岂不是完美。但是还要顺便一句,redis的连接在空闲一段时间后,服务端可能会主动断开,Blpop命令会抛出异常,所以还要做好了重试或者其他策略为好。
3. 如果作为专业的消息队列,一个消息被多个不同的业务消费(一个消息被消费多次)是必须要支持的,但是redis是基于自己的list数据结构来实现的伪队列,所以这种业务场景下就不要考虑redis了,或者自己封装一个类似分发器的中间件也可以。
4. 基于redis的消息队列没有Ack的保证,换句话说,一个消息是否被正常处理redis是不知道的,这在很大程度上限制了它的适用场景。
写在最后
我还是建议不要用redis做专业的MQ使用,毕竟MQ这种场景不是redis的设计初衷,但是太多人把redis做MQ使用,于是redis的作者基于redis的核心代码实现了一个消息队列:disque,也许未来会作为redis的核心组件,地址为 https://github.com/antirez/disque
除了disque,Redis Stream也是一个把redis作为MQ的比较好的解决方案,有兴趣的同学可以研究一下。
千万不要把任何一个业务场景想象的太简单
特别推荐一个分享架构+算法的优质内容,还没关注的小伙伴,可以长按关注一下:长按订阅更多精彩▼如有收获,点个在看,诚挚感谢
Redis做消息队列,香吗?相关推荐
- 使用redis做消息队列mq的总结
总结 目前使用redis做消息队列的的方式有3中,list, publish/subscribe, stream list做mq的总结 使用方法 1. 生产者可以 lpush 写 ...
- 程序员过关斩将--redis做消息队列,香吗?
菜菜哥,我刚做完了一个订单系统,感觉很简单呀 说说看,大量的订单状态怎么处理的? 我设计的时候可是考虑了这一点,所以用了异步处理,采用了MQ 那用的什么MQ呢,透露一下呗 我用的redis做的MQ,很 ...
- php redis查看队列长度,php redis做消息队列解决流量削峰常用的5个指令
线上的秒杀等业务场景,需要类似的解决方案,需要平安度过同时抢购带来的流量峰值的问题.如果此时还用mysql做消息队列是什么容易挂掉的,如果死轻量级的秒杀我们完全可以用redis来应对. 削峰从本质上来 ...
- 使用Redis Stream来做消息队列和在Asp.Net Core中的实现
Redis - Wikipedia 写在前面 我一直以来使用redis的时候,很多低烈度需求(并发要求不是很高)需要用到消息队列的时候,在项目本身已经使用了Redis的情况下都想直接用Redis来做消 ...
- PHP + Redis 实现消息队列
Redis做消息队列的好处在于它的轻量级,高并发,延迟敏感,应用场景有 即时数据分析.秒杀计数器.缓存等 Redis做消息队列待解决的问题: 1.消息的可靠性: 没有相应的机制保证消息的消费,当消费者 ...
- springboot使用redis实现消息队列功能,redis使用list和stream实现消息队列功能,redis实现消息队列的风险点分析
文章目录 写在前面 基于list的消息队列解决方案 使用list基本实现消息队列 阻塞式消费,避免性能损失 替换while(true) 实现消息幂等 保证消息可靠性 基于stream的消息队列解决方案 ...
- aliyun redis 链接超时_用redis做异步队列,原来还可以这样
Redis设计主要是用来做缓存的,但是由于它自身的某种特性使得它可以用来做消息队列. 它有几个阻塞式的API可以使用,正是这些阻塞式的API让其有能力做消息队列: 另外,做消息队列的其他特性例如FIF ...
- 用redis实现消息队列(实时消费+ack机制)【转】
用redis实现消息队列(实时消费+ack机制) java queue 消息队列 redis 消息队列 首先做简单的引入. MQ主要是用来: 解耦应用. 异步化消息 流量削峰填谷 目前使用的较多的有A ...
- 使用Redis 实现消息队列
一 .为什么要用Redis实现轻量级MQ? MQ的主要作用: 应用解耦 异步化消息 流量削峰填谷 目前使用比较多的是ActiveMQ . RabbitMQ . ZeroMQ . Kafka . Met ...
最新文章
- Rocksdb 写流程,读流程,WAL文件,MANIFEST文件,ColumnFamily,Memtable,SST文件原理详解
- UA MATH 571B Tukey‘s Test for Non-additivity
- Excel列数和列字母的转换(column number 和 column letters 互转)
- 面试必胜的九大素质八大能力
- DB Intro - MongoDB User
- 想入职AI算法岗?BAT的工程师去学了这门课
- 求周期字符串的最小子串
- vantUI组件:Grid宫格 - 案例篇
- [ABP开源项目]--vue+vuex+vue-router+EF的权限管理系统
- MySQL二进制部署
- Create a Search Scope for a Sharepoint 2010 List or Library
- visual studio 各版本 激活码
- Angular SSR 探究
- 网页导出pdf不完整_偶尔偷个懒吧:3种pdf文献全文一键翻译的方法
- 【电脑讲解】笔记本怎么连接宽带,拨号和无线网络连接方法
- 分水岭算法(学习笔记)
- UE5分屏(小地图)的解决方案
- pythoncookie自动登录_Python使用cookie 免密登录了解一下
- 电脑C盘满了怎么清理比较好
- 从源码角度分析Android中的Binder机制的前因后果
热门文章
- linux的共享内存,linux共享内存实际在哪里?
- word怎么根据点画曲线_圆锥曲线联解公式
- 点分治问题 ----------- P3727 曼哈顿计划E[点分治+博弈SG函数打表找规律]
- Matlab入门笔记
- mysql innodb myisam 插入数据_mysql innodb换成myisam后插入数据变快?
- dp背包九讲(待补充,暂时前两讲)
- 客户端修改文件服务器密码,客户端服务器登录 密码问题
- problem h: 一年中的第几天_一年级语文26个汉语拼音字母表读法+写法+笔顺,给孩子收藏!...
- PHP访问mysql的常用函数,PHP操作MySQL数据库常用函数
- 什么是java多线程_什么是java多线程,java多线程的基本原理?