通常來講,消息隊列有兩種場景,一種是發佈者訂閱者模式,一種是生產者消費者模式。利用redis這兩種場景的消息隊列都可以實現。
定義:html
那麼如此多的MQ產品,爲何要使用redis做消息隊列呢?如下附上一份總結了別人的一些report或blog的表格,以及當初用來講服整個team的一句結論。redis
MQ | Env. | Weight | Disadvantage | |||
RabbitMQ | Erlang | Heavy | Bad scalability;Low speed; | |||
ZeroMQ | C | Light | difficult for development | |||
ActiveMQ | Java | - | Low performance | |||
Redis | C | - | Low performance while enqueuing big data (>= 10k) |
Redis is easy to use and configure since we have experience in Redis, and most importantly, its performance satisfies our requirement.
ui
Then, how to use redis as a MQ?spa
首先,redis的隊列實際在代碼邏輯中不須要由咱們本身實現,所以一個所謂的 RedisMQ 對象實際是一個 redis key以及對其操做的一些封裝。scala
PubSub Mode:code
redis 從 2.0.0 版本開始支持 pub/sub 指令。詳情見 http://redis.io/topics/pubsuborm
實現思想很簡單,Publisher調用redis的publish方法往特定的channel發送消息,Subscriber在初始化的時候要subscribe到該channel,一旦有消息就會當即接收。htm
比較簡單的demo可參見:http://shift-alt-ctrl.iteye.com/blog/1867454 ,此連接博客中寫得已較詳細,本文便再也不贅述。對象
Producer/Consumer Mode:blog
該方法是藉助redis的list結構實現的。
Producer調用redis的lpush往特定key裏塞入消息,Consumer調用brpop去不斷監聽該key。
producer:
1 // producer code 2 String key = "demo:mq:test"; 3 String msg = "hello world"; 4redisDao.lpush(key, msg);
consumer:
1 // consumer code 2 String key = "demo:mq:test"; 3 while (true) { 4 // block invoke 5 List<String> msgs = redisDao.brpop(BLOCK_TIMEOUT, listKey); 6 if (msgs == null) continue; 7 String jobMsg = msgs.get(1); 8 processMsg(jobMsg); 9 }
當有多個consumers的時候,它會按照brpop調用的順序分派消息,並不是隨機。
BLOCK_TIMEOUT不建議設成infinity(有些redis驅動也直接不支持inifinity),咱們目前設成30(單位是秒)狀況良好。