关于redis:Redis做消息队列全攻略

53次阅读

共计 2400 个字符,预计需要花费 6 分钟才能阅读完成。

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 命令会抛出异样,所以还要做好了重试或者其余策略为好。

  1. 如果作为业余的音讯队列,一个音讯被多个不同的业务生产(一个音讯被生产屡次)是必须要反对的,然而 redis 是基于本人的 list 数据结构来实现的伪队列,所以这种业务场景下就不要思考 redis 了,或者本人封装一个相似散发器的中间件也能够。
  2. 基于 redis 的音讯队列没有 Ack 的保障,换句话说,一个音讯是否被失常解决 redis 是不晓得的,这在很大水平上限度了它的实用场景。

写在最初

我还是倡议不要用 redis 做业余的 MQ 应用,毕竟 MQ 这种场景不是 redis 的设计初衷,然而太多人把 redis 做 MQ 应用,于是 redis 的作者基于 redis 的外围代码实现了一个音讯队列:disque,兴许将来会作为 redis 的外围组件, 地址为 https://github.com/antirez/di…

除了 disque,Redis Stream 也是一个把 redis 作为 MQ 的比拟好的解决方案,有趣味的同学能够钻研一下。

千万不要把任何一个业务场景设想的太简略

更多精彩文章

  • 分布式大并发系列
  • 架构设计系列
  • 趣学算法和数据结构系列
  • 设计模式系列

正文完
 0