我们习惯于用rabbitmq和kafka作为消息中间件,来给应用之间增加异步的能力。但是使用过的同学都知道,使用专业的消息中间件使用起来非常复杂,我们实现一个简单的功能都需要大量的操作。有了redis,可以让我解脱出来,使用redis可以非常轻松的搞定,Redis的消息队列不是专业的消息中间件,没有非常高级的特性,如果对消息的可靠性有极高的追求,那么redis的消息中间件可能不适合。
异步消息队列
Redis的列表可以用来处理消息队列,使用rpush和lpush操作入队列,用lpop和rpop用来操作出队列。
> rpush notify-queue apple banana pear
(integer) 3
> llen notify-queue
(integer) 3
> lpop notify-queue
"apple"
> llen notify-queue
(integer) 2
> lpop notify-queue
"banana"
> llen notify-queue
(integer) 1
> lpop notify-queue
"pear"
> llen notify-queue
(integer) 0
> lpop notify-queue
(nil)
上面就是队列的操作使用。
队列空了怎么办
客户端通过pop来获取数据,处理完成,再从队列中获取新的数据,如此循环往复。这就是作为队列消费者的生命周期。
可是如果队列空了怎么办,客户端就会陷入pop的死循环。不停的pop,没有数据,再进行pop。这就是浪费生命的空轮询。空轮询不仅拉高了客户端的cpu,redis的QPS也会被拉高。那么怎么办呢
改进1:通常让线程休息1s,睡醒后再进行拉取。不仅客户端的cpu能够降下来,Redis的QPS也能降下来了。
Thread.sleep(1000) #JAVA
队列延时
上面的让客户端睡1秒,虽然能够解决一些问题,但是睡眠会导致消息的延迟。如果单线程让线程睡1s就是延迟1s,如果多个客户端呢?
有没有什么办法可以更好的解决这个问题呢?
当然,可以使用blpop和brpop,也就是阻塞读,堵塞读在没有数据时会进入休眠状态,有数据是立马被激活,消息的延迟性几乎为0。
空连接自动断开
如果线程一直被阻塞在哪里,客户端连接就成了闲置连接,闲置过久,服务器一般会主动断开连接,减少闲置资源占用,这个时候blpop和brpo会抛出异常来,在编写代码时格外注意,还要重试。
锁冲突问题
如果加锁没有成功,一般可以通过3中策略来处理加锁失败:
1.直接抛出异常,通知用户稍后再试。这种一般用于用户的直接请求。
2.sleep一会再重试
3.将请求转移至延迟队列中,过一会再试
原文地址:https://www.cnblogs.com/lonelyxmas/p/12515046.html