不使用平时习惯的Rabbitmq和Rocketmq的消息中间件来实现应用程序之间异步消息传递功能,你怎么拿Redis来实现呢?
基于Redis实现阻塞队列
要基于Redis来实现队列功能,我们就得看Redis的一种数据结构 列表 list 来作为异步消息功能的传递 用列表里面的命令 lpush和 rpop 或者 rpush 和 lpop 来操作队列 如下图
分开画只是更加明白要实现队列的的生产方向跟订阅方向

而Redis的队列也符合消息队列的本质 支持多个生产者与消费者

知道思路可是,如果队列空了怎么办
客户端通过队列的 pop 操作来获取消息,然后进行处理。处理完了再接着获取消息,再进行处理。如此循环,这便是作为队列消费者的客户端的生命周期。可是如果队列空了,客户端就会陷入 pop 的死循环,不停地 pop,没有数据,接着再 pop,还没有数据。这就是浪费生命的空轮询。空轮询不但拉高了客户端的CPU消耗,Redis 的 QPS 也会被拉高,如果这样空轮询的客户端有几十个,Redis的慢查询可能会显著增多。
1.通常我们使用 sleep 来解决这个问题,让线程睡一会,睡个 1s 就可以了。不但客户端的CPU消耗能降下来,Redis 的 QPS 也降下来了
2.用上面睡眠的办法可以解决问题。但是又有个小问题,那就是睡眠会导致消息的延迟增大。如果只有 1 个消费者,那么这个延迟就是 1s。如果有多个消费者,这个延迟会有所下降,因为每个消费者的睡眠时间是岔开的。有什么办法能显著降低延迟呢?你当然可以很快想到:那就把睡眠的时间缩短点。这种方法当然可以,不过有没有更好的解决方案呢?当然也有,那就是blpop/brpop。
你以为上面的方案真的很完美吗?先别急着开心,其实它还有个问题需要解决。什么问题呢?答案是:空闲连接的问题。
如果线程一直阻塞在那里,Redis 的客户端连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减少闲置资源占用。这个时候 blpop/brpop 会抛出异常。所以编写客户端消费者的时候要小心,如果捕获到异常,还要重试
