關於 Redis的訂閱發布
文章目錄
- 1. 為什麼做訂閱分布?
- 2. Redis中的訂閱發布
- 3. Redis生產者消費者
- 4. Redis中訂閱發布
- 5. Java Jedis踩過的坑
為什麼做訂閱分布?隨著業務複雜, 業務的項目依賴關係增強, 使用訊息佇列協助系統降低耦合度
.
- 訂閱分布本身也是一種生產者消費者模式, 訂閱者是消費者, 發行者是生產者.
- 訂閱發布模式, 發行者發布訊息後, 只要有訂閱者, 則多個訂閱者會收到同樣的訊息
生產者消費者模式, 生產者往隊列裡放入訊息, 由多個消費者對一條訊息進行搶佔.
訂閱分布模式可以將一些不著急完成的工作放到其他進程或者線程中進行離線處理.
Redis中的訂閱發布Redis中的訂閱發布模式, 當沒有訂閱者時, 訊息會被直接丟棄(Redis不會持久化儲存訊息)
Redis生產者消費者生產者使用Redis中的list資料結構進行實現, 將待處理的訊息塞入到訊息佇列中.
1234567891011 |
class Producer(object): def __init__(self, host="localhost", port=6379):self._conn = redis.StrictRedis(host=host, port=port)self.key = "test_key"self.value = "test_value_{id}" def produce(self):for id in xrange(5):msg = self.value.format(id=id)self._conn.lpush(self.key, msg) |
消費者使用redis中brpop
進行實現, brpop會從list頭部訊息, 並能夠設定逾時等待時間.
12345678910111213141516171819202122232425 |
class Consumer(object): def __init__(self, host="localhost", port=6379):self._conn = redis.StrictRedis(host=host, port=port)self.key = "test_key" def consume(self, timeout=0):# timeout=0 表示會無線阻塞, 直到獲得訊息while True:msg = self._conn.brpop(self.key, timeout=timeout)process(msg) def process(msg):print msg if __name__ == '__main__':consumer = Consumer()consumer.consume()# 輸出結果('test_key', 'test_value_1')('test_key', 'test_value_2')('test_key', 'test_value_3')('test_key', 'test_value_4')('test_key', 'test_value_5') |
Redis中訂閱發布在Redis Pubsub中, 一個頻道(channel)相當於一個訊息佇列
1234567891011 |
class Publisher(object): def __init__(self, host, port):self._conn = redis.StrictRedis(host=host, port=port)self.channel = "test_channel"self.value = "test_value_{id}" def pub(self):for id in xrange(5):msg = self.value.format(id=id)self._conn.publish(self.channel, msg) |
其中get_message
使用了select
IO多工來檢查socket串連是否是否可讀.
1234567891011121314151617181920212223 |
class Subscriber(object): def __init__(self, host="localhost", port=6379):self._conn = redis.StrictRedis(host=host, port=port)self._pubsub = self._conn.pubsub() # 產生pubsub對象self.channel = "test_channel"self._pubsub.subscribe(self.channel) def sub(self):while True:msg = self._pubsub.get_message()if msg and isinstance(msg.get("data"), basestring):process(msg.get("data")) def close(self):self._pubsub.close() # 輸出結果test_value_1test_value_2test_value_3test_value_4test_value_5 |
Java Jedis踩過的坑在Jedis中訂閱者處理是採用同步的方式, 看源碼中PubSub模組的process函數
在do-while
迴圈中, 會等到當前訊息處理完畢才能夠處理下一條訊息, 這樣會導致當入隊列訊息量過大的時候, redis連結被強制關閉.
解決方案: 將整個處理函數改為非同步方式.
下面關於Redis��文章您也可能喜歡,不妨參考下:
Ubuntu 14.04下Redis安裝及簡單測試
Redis主從複製基本配置
Redis叢集明細文檔
Ubuntu 12.10下安裝Redis(圖文詳解)+ Jedis串連Redis
Redis系列-安裝部署維護篇
CentOS 6.3安裝Redis
Redis安裝部署學習筆記
Redis設定檔redis.conf 詳解
Redis 的詳細介紹:請點這裡
Redis 的:請點這裡
本文永久更新連結地址: