消息隊(duì)列,Message Queue,常用于解決并發(fā)系統(tǒng)中的資源一致性問(wèn)題,提升峰值的處理能力,同時(shí)保證消息的順序性、可恢復(fù)性、必送達(dá)性,對(duì)應(yīng)用進(jìn)行解耦,或者實(shí)現(xiàn)異步通訊等。 (推薦學(xué)習(xí):Redis視頻教程)
市面上的 MQ應(yīng)用有很多(例如:Kafka,RabbitMQ,Disque),同時(shí)也可以基于 Redis 來(lái)實(shí)現(xiàn),比較典型的方案有:
基于List的 LPUSH+BRPOP 的實(shí)現(xiàn)
PUB/SUB,訂閱/發(fā)布模式
基于Sorted-Set的實(shí)現(xiàn)
基于Stream類型的實(shí)現(xiàn)
在消息隊(duì)列使用中,有生產(chǎn)者producter和消費(fèi)者consumer。生產(chǎn)者負(fù)責(zé)生成消息,消費(fèi)者負(fù)責(zé)使用處理消息。
生產(chǎn),指的是將消息放入消息隊(duì)列。
消費(fèi),指的是讀取并處理消息。通常一個(gè)消息再被消費(fèi)后,就應(yīng)該從消息隊(duì)列中刪除。
基于List的 LPUSH+BRPOP 的實(shí)現(xiàn)
典型的命令為:
LPUSH,將消息隊(duì)列 BRPOP,從隊(duì)列中取出消息,阻塞模式
就是一個(gè)典型的基于FIFL隊(duì)列的解決方案。其中LPUSH是生產(chǎn)者做的事,而B(niǎo)RPOP是消費(fèi)者做的事。
該模式有很多優(yōu)點(diǎn):
實(shí)現(xiàn)簡(jiǎn)單
Reids支持持久化消息,意味著消息不會(huì)丟失,可以重復(fù)查看(注意不是消費(fèi),只看不用,LRANGE類的指令)。
可以保證順序,保證使用LPUSH命令,可以保證消息的順序性
使用RPUSH,可以將消息放在隊(duì)列的開(kāi)頭,達(dá)到優(yōu)先消息的目的,可以實(shí)現(xiàn)簡(jiǎn)易的消息優(yōu)先隊(duì)列。
同時(shí)也有些劣勢(shì):
做消費(fèi)確認(rèn)ACK比較麻煩,就是不能保證消費(fèi)者在讀取之后,未處理后的宕機(jī)問(wèn)題。導(dǎo)致消息意外丟失。通常需要自己維護(hù)一個(gè)Pending列表,保證消息的處理確認(rèn)。
不能做廣播模式,例如典型的Pub/Discribe模式。
不能重復(fù)消費(fèi),一旦消費(fèi)就會(huì)被刪除
不支持分組消費(fèi),需要自己在業(yè)務(wù)邏輯層解決
PUB/SUB,訂閱/發(fā)布模式
SUBSCRIBE,用于訂閱信道 PUBLISH,向信道發(fā)送消息 UNSUBSCRIBE,取消訂閱
生產(chǎn)者和消費(fèi)者通過(guò)相同的一個(gè)信道(Channel)進(jìn)行交互。信道其實(shí)也就是隊(duì)列。通常會(huì)有多個(gè)消費(fèi)者。多個(gè)消費(fèi)者訂閱同一個(gè)信道,當(dāng)生產(chǎn)者向信道發(fā)布消息時(shí),該信道會(huì)立即將消息逐一發(fā)布給每個(gè)消費(fèi)者??梢?jiàn),該信道對(duì)于消費(fèi)者是發(fā)散的信道,每個(gè)消費(fèi)者都可以得到相同的消息。典型的對(duì)多的關(guān)系。
典型的優(yōu)點(diǎn)是:
典型的廣播模式,一個(gè)消息可以發(fā)布到多個(gè)消費(fèi)者
多信道訂閱,消費(fèi)者可以同時(shí)訂閱多個(gè)信道,從而接收多類消息
消息即時(shí)發(fā)送,消息不用等待消費(fèi)者讀取,消費(fèi)者會(huì)自動(dòng)接收到信道發(fā)布的消息
也有些缺點(diǎn):
消息一旦發(fā)布,不能接收。換句話就是發(fā)布時(shí)若客戶端不在線,則消息丟失,不能尋回
不能保證每個(gè)消費(fèi)者接收的時(shí)間是一致的
若消費(fèi)者客戶端出現(xiàn)消息積壓,到一定程度,會(huì)被強(qiáng)制斷開(kāi),導(dǎo)致消息意外丟失。通常發(fā)生在消息的生產(chǎn)遠(yuǎn)大于消費(fèi)速度時(shí)
可見(jiàn),Pub/Sub 模式不適合做消息存儲(chǔ),消息積壓類的業(yè)務(wù),而是擅長(zhǎng)處理廣播,即時(shí)通訊,即時(shí)反饋的業(yè)務(wù)。
基于SortedSet有序集合的實(shí)現(xiàn)
ZADD KEY score member,壓入集合 ZRANGEBYSCORE,依據(jù)score獲取成員
有序集合的方案是在自己確定消息順I(yè)D時(shí)比較常用,使用集合成員的Score來(lái)作為消息ID,保證順序,還可以保證消息ID的單調(diào)遞增。通??梢允褂脮r(shí)間戳+序號(hào)的方案。確保了消息ID的單調(diào)遞增,利用SortedSet的依據(jù)Score排序的特征,就可以制作一個(gè)有序的消息隊(duì)列了。
和上面的方案相比,優(yōu)點(diǎn)就是可以自定義消息ID,在消息ID有意義時(shí),比較重要。缺點(diǎn)也明顯,不允許重復(fù)消息(以為是集合),同時(shí)消息ID確定有錯(cuò)誤會(huì)導(dǎo)致消息的順序出錯(cuò)。
所以,若不是需要自定義消息ID,這個(gè)方案好像有點(diǎn)雞肋…
基于 Stream 類型的實(shí)現(xiàn)
這個(gè)Stream類型redis就是為了實(shí)現(xiàn)消息隊(duì)列的。支持自動(dòng)生成消息ID,分組消費(fèi),ACK,消息轉(zhuǎn)移,隊(duì)列監(jiān)控等核心消息隊(duì)列功能