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
缺点
音讯队列的实质还是消费者和生产者的问题,只有是这样的场景,就会波及到两端不均衡的状况,具体可体现为:
- 生产者生产速度大于消费者生产速度,面临音讯一直沉积的问题,随着音讯数据的沉积,队列是开启限流措施,还是抛弃某些音讯,更或者是把音讯数据进行长久化。对于基于redis实现的音讯队列,个别为可忍受局部音讯失落的业务,所以很多人抉择抛弃音讯的计划。另一种计划是基于redis单线程机制,能够减少消费者数量,这也是仅仅针对音讯只被生产一次的场景。当然也能够抉择长久化计划,然而会对redis的性能产生影响。
- 消费者生产速度大于生产者生产速度,有的同学会说,这样挺好啊,是,在某种意义上是比反过来的那个场景要好一些,毕竟能够防止产生音讯的沉积问题。然而消费者没有音讯生产,会导致消费者过程始终在那里节约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命令会抛出异样,所以还要做好了重试或者其余策略为好。
- 如果作为业余的音讯队列,一个音讯被多个不同的业务生产(一个音讯被生产屡次)是必须要反对的,然而redis是基于本人的list数据结构来实现的伪队列,所以这种业务场景下就不要思考redis了,或者本人封装一个相似散发器的中间件也能够。
- 基于redis的音讯队列没有Ack的保障,换句话说,一个音讯是否被失常解决redis是不晓得的,这在很大水平上限度了它的实用场景。
写在最初
我还是倡议不要用redis做业余的MQ应用,毕竟MQ这种场景不是redis的设计初衷,然而太多人把redis做MQ应用,于是redis的作者基于redis的外围代码实现了一个音讯队列:disque,兴许将来会作为redis的外围组件,地址为 https://github.com/antirez/di...
除了disque,Redis Stream也是一个把redis作为MQ的比拟好的解决方案,有趣味的同学能够钻研一下。
千万不要把任何一个业务场景设想的太简略
更多精彩文章
- 分布式大并发系列
- 架构设计系列
- 趣学算法和数据结构系列
- 设计模式系列