Redis 的pub/sub機制與23種設計模式中的觀察者設計模式極為類似。但Redis對於這個機制的實現更為輕便和簡結,沒有觀察者模式的那麼複雜的邏輯考慮而僅僅需要通過兩個Redis用戶端配置channel即可實現,因此它也僅僅做了訊息的”發布”和”訂閱”的實現,而在實際處理這類情境時遇到的情況根本沒有考慮到。
資料可靠性無法保證
一個redis-cli發布訊息n個redis-cli接受訊息。訊息的發布是無狀態的,即發布完訊息後該redis-cli便在理會該訊息是否被接受到,是否在傳輸過程中丟失,即對於發行者來說,訊息是”即發即失”的.
擴充性太差
不能通過增加消費者來加快消耗發行者的寫入的資料,如果發行者發布的訊息很多,則資料阻塞在通道中已等待被消費著來消耗。阻塞時間越久,資料丟失的風險越大(網路或者伺服器的一個不穩定就會導致資料的丟失)
資源消耗較高
在pub/sub中訊息發行者不需要獨佔一個Redis的連結,而消費者則需要單獨佔用一個Redis的連結,在java中便不得獨立出分出一個線程來處理消費者。這種情境一般對應這多個消費者,此時則有著過高的資源消耗。
對於如上的幾種不足,如果在項目中需要考慮的話可以使用JMS來實現該功能。JMS提供了訊息的持久化/耐久性等各種企業級的特性。如果依然想使用Redis來實現並做一些資料的持久化操作,則可以根據JMS的特性來通過Redis類比出來. subscribe端首先向一個Set集合中增加“訂閱者ID”,此Set集合儲存了“活躍訂閱”者,訂閱者ID標記每個唯一的訂閱者,例如:sub:email,sub:web。此SET稱為“活躍訂閱者集合” subcribe端開啟訂閱操作,並基於Redis建立一個以“訂閱者ID”為KEY的LIST資料結構,此LIST中儲存了所有的尚未消費的訊息。此LIST稱為“訂閱者訊息佇列” publish端:每發布一條訊息之後,publish端都需要遍曆“活躍訂閱者集合”,並依次向每個“訂閱者訊息佇列”尾部追加此次發布的訊息。 到此為止,我們可以基本保證,發布的每一條訊息,都會持久儲存在每個“訂閱者訊息佇列”中。 subscribe端,每收到一個訂閱訊息,在消費之後,必須刪除自己的“訂閱者訊息佇列”頭部的一條記錄。 subscribe端啟動時,如果發現自己的自己的“訂閱者訊息佇列”有殘存記錄,那麼將會首先消費這些記錄,然後再去訂閱。
代碼我明天實現了在貼出來,今晚先睡了。。晚安。