本篇文章為大家展示了redis中怎么實(shí)現(xiàn)生產(chǎn)消費(fèi)模式,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
網(wǎng)站的建設(shè)創(chuàng)新互聯(lián)公司專注網(wǎng)站定制,經(jīng)驗(yàn)豐富,不做模板,主營(yíng)網(wǎng)站定制開發(fā).小程序定制開發(fā),H5頁面制作!給你煥然一新的設(shè)計(jì)體驗(yàn)!已為成都水處理設(shè)備等企業(yè)提供專業(yè)服務(wù)。
簡(jiǎn)單隊(duì)列實(shí)現(xiàn)
那么我們Redis剛好有一個(gè)數(shù)據(jù)類型符合這個(gè)就是List。list可以實(shí)現(xiàn)隊(duì)列(先進(jìn)先出)和棧(先進(jìn)后出),那么這個(gè)list又有兩種插入數(shù)據(jù)的方式:頭插法和尾插法。所以我們今天使用的結(jié)構(gòu)是隊(duì)列,使用尾插法,關(guān)鍵的命令有rpush(尾插)和lpop(頭部獲取)。如下圖所示:
> rpush squeue zhangsan lisi mango #插入隊(duì)列(integer) 3> lpop squeue #獲取隊(duì)列"zhangsan"> rpush squeue wangwu(integer) 3> lpop squeue"lisi"> lpop squeue"mango"> lpop squeue"wangwu"> lpop squeue #空隊(duì)列(nil)
上面是rpush/lpop結(jié)合使用的例子。還可以使用lpush/rpop結(jié)合使用,效果是一樣的。
注意:我們這里思考一個(gè)問題,在咱們實(shí)際開發(fā)中我們獲取隊(duì)列數(shù)據(jù)的時(shí)候如果這個(gè)隊(duì)列里面沒有任何值了,我們會(huì)一直pop,這樣我們的程序出現(xiàn)了一個(gè)死循環(huán),而且此時(shí)的redis會(huì)不斷的處理服務(wù)器的pop指令使之內(nèi)存增高。
此時(shí)mango靈光一閃,每次pop的時(shí)候判斷,如果隊(duì)列有值我們獲取這個(gè)值進(jìn)行操作,如果隊(duì)列是空隊(duì)列,那么我們此時(shí)休息三秒鐘再請(qǐng)求,emmm,加雞腿。
> lpop squeue #空隊(duì)列(nil).......sleep 3s old> lpop squeue...
通過后端程序控制redis服務(wù)器休息時(shí)間是一個(gè)好辦法,但是此處有一個(gè)問題,如果說服務(wù)器在休眠的時(shí)候隊(duì)列突然進(jìn)來一個(gè)值,而此時(shí)需要及時(shí)反應(yīng)獲取這個(gè)值該如何實(shí)現(xiàn)呢?
當(dāng)然,redis早就考慮到這個(gè)問題,so提供了一個(gè)叫做隊(duì)列阻塞讀,其命令blpop和brpop,就是lpop和rpop的阻塞讀方法
blpop [第一個(gè)參數(shù):key]... [第二個(gè)參數(shù):time]key可以有多個(gè)key等待time就是阻塞時(shí)間,單位默認(rèn)為秒
嗯,看似完美的解決了上面的方法
問題又來了,如果說此處設(shè)置的時(shí)間稍微長(zhǎng)一點(diǎn),阻塞請(qǐng)求的客戶端連接再多一點(diǎn)那么會(huì)出現(xiàn)下一個(gè)問題,那就是空閑連接問題。如果線程一直阻塞在哪里,Redis的客戶端連接就成了閑置連接,閑置過久,服務(wù)器一般會(huì)主動(dòng)斷開連接,減少閑置資源占用。這個(gè)時(shí)候blpop/brpop會(huì)拋出異常來。
所以,魚與熊掌不可兼得,開發(fā)者當(dāng)注意此處需要捕獲異常,然后重新請(qǐng)求。
上面我們介紹了阻塞隊(duì)列,深知空閑連接會(huì)被回收出現(xiàn)異常問題,那么我們可不可以實(shí)現(xiàn)延遲隊(duì)列,我提前一段時(shí)間比如5秒獲取隊(duì)列中的元素,當(dāng)元素記錄的時(shí)間到達(dá)了我再去執(zhí)行這個(gè)值,然后又提前5秒時(shí)間去獲取隊(duì)列中的值,依次反復(fù)。即可保證我在某一時(shí)刻去執(zhí)行隊(duì)列中對(duì)應(yīng)時(shí)間的值。
我們來分析,首先保證隊(duì)列是一個(gè)有序的我們才能依次執(zhí)行,這里我們使用ZSet因?yàn)樗鼛в信判蚯也恢貜?fù),保證客戶端沒有提交重復(fù)數(shù)據(jù),那么值保證了,這個(gè)排序如何設(shè)計(jì)呢?我們不能使用'yyyyMMddHHmmssSSS'這種,第一個(gè)不適應(yīng)這個(gè)排序類型可能會(huì)超出,第二就是每次轉(zhuǎn)換會(huì)帶來運(yùn)算轉(zhuǎn)換的消耗,所有這里我們使用時(shí)間戳。那么zset提供一個(gè)獲取某段存在數(shù)據(jù)指令zrangebyscore,這個(gè)指令能夠獲取到我們想要的數(shù)據(jù),然后通過zrem刪除zset里面的值即可完成消費(fèi)。
####假設(shè)當(dāng)前時(shí)間戳是0> zadd dqueue 4 zhangsan 8 lisi 12 mango #添加元素(integer) 3####提前獲取后5秒的數(shù)據(jù)> zrangebyscore dqueue -inf 5 withscores #提前獲取5秒內(nèi)的數(shù)據(jù)1) "zhangsan" #值2) 4.0 #當(dāng)前排序索引> zrem dqueue zhangsan #消費(fèi)后刪除元素1####當(dāng)前時(shí)間戳來到了5秒,提前5秒獲取就加上這個(gè)> zrangebyscore dqueue -inf 10 withscores #獲取10以內(nèi)的數(shù)據(jù),輪訓(xùn)調(diào)用1) "lisi"2) 8.0
上述內(nèi)容就是Redis中怎么實(shí)現(xiàn)生產(chǎn)消費(fèi)模式,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。