我在生產項目裏是如何使用Redis發佈訂閱的?(一)使用場景

轉載請註明出處!html

導語redis

Redis是咱們很經常使用的一款nosql數據庫產品,咱們一般會用Redis來配合關係型數據庫一塊兒使用,彌補關係型數據庫的不足。sql

其中,Redis的發佈訂閱功能也是它的一大亮點。雖然它不是一款專門作發佈訂閱的產品,但其自帶的發佈訂閱功能已經知足咱們平常需求了。數據庫

那Redis的發佈訂閱功能均可以用在哪些場景呢?我在生產項目裏又是如何使用Redis發佈訂閱的?今天咱們就來探討一下這個問題。編程

 

什麼是發佈訂閱緩存

所謂發佈訂閱,就是消息發佈者發佈消息及消息訂閱者接收消息,兩者經過某種媒介關聯起來。這相似之前的『訂報』,當咱們訂閱了某種報紙後(好比財經報),每當報紙有新的期刊出版後,就會有郵遞員給咱們送過來。即,只有定了這種報紙纔會收到出版社發佈的這種新報紙。app

 

Redis的發佈訂閱功能也是相似,首先要有消息的發佈者,其次要有消息的訂閱者。有了消息發佈者和訂閱者以後,還缺乏什麼?異步

 

那就是上述的『某種報紙』,並非出版社出版的每一種報紙(如人民日報,財經報,體育報)都給你送過來,而是明確你要定哪種,你定了哪種纔給你送哪種。nosql

 

回到Redis的發佈訂閱上,上述的『某種報紙』就抽象爲頻道channel,客戶端訂閱了某channel後,當發佈者經過此channel發佈消息時,全部訂閱者就會收到該頻道發佈的消息。url

發佈和訂閱機制

當一個客戶端經過 PUBLISH 命令向訂閱者發送信息的時候,咱們稱這個客戶端爲發佈者(publisher)。

而當一個客戶端使用 SUBSCRIBE 或者 PSUBSCRIBE命令接收信息的時候,咱們稱這個客戶端爲訂閱者(subscriber)。

爲了解耦發佈者(publisher)和訂閱者(subscriber)之間的關係,Redis 使用了 channel (頻道)做爲二者的中介 —— 發佈者將信息直接發佈給 channel ,而 channel 負責將信息發送給適當的訂閱者,發佈者和訂閱者之間沒有相互關係,也不知道對方的存在。

 

如上圖所示,`Redis client A` 和 `Redis client B` 訂閱了 `channel`-> `Financial newspapers`,當 `Redis client C`經過  `channel`->`Financial newspapers` 發佈消息 `Stocks are up today!` 時,`Redis client A` 和 `Redis client B` 就會收到該消息。

 

原理

Redis是使用C實現的,經過分析 Redis 源碼裏的 pubsub.c 文件,瞭解發佈和訂閱機制的底層實現,籍此加深對 Redis 的理解。

 

Redis 經過 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令實現發佈和訂閱功能。

經過 SUBSCRIBE 命令訂閱某頻道後,redis-server 裏維護了一個字典,字典的鍵就是一個個 channel ,而字典的值則是一個鏈表,鏈表中保存了全部訂閱這個 channel 的客戶端。SUBSCRIBE 命令的關鍵,就是將客戶端添加到給定 channel 的訂閱鏈表中。

經過 PUBLISH 命令向訂閱者發送消息,redis-server 會使用給定的頻道做爲鍵,在它所維護的 channel 字典中查找記錄了訂閱這個頻道的全部客戶端的鏈表,遍歷這個鏈表,將消息發佈給全部訂閱者。

發佈訂閱的原理詳細參考:https://www.cnblogs.com/duanxz/p/6053520.html

 

我在哪些業務場景使用Redis發佈訂閱?

明確了Redis發佈訂閱的原理和基本流程後,咱們來看一下Redis的發佈訂閱到底具體能作什麼。

一、異步消息通知

好比渠道在調支付平臺的時候,咱們能夠用回調的方式給支付平臺一個咱們的回調接口來通知咱們支付狀態,還能夠利用Redis的發佈訂閱來實現。好比咱們發起支付的同時訂閱頻道`pay_notice_` + `wk` (假如咱們的渠道標識是wk,不能讓其餘渠道也訂閱這個頻道),當支付平臺處理完成後,支付平臺往該頻道發佈消息,告訴頻道的訂閱者該訂單的支付信息及狀態。收到消息後,根據消息內容更新訂單信息及後續操做。 

當不少人都調用支付平臺時,支付時都去訂閱同一個頻道會有問題。好比用戶A支付完訂閱頻道`pay_notice_wk`,在支付平臺未處理完時,用戶B支付完也訂閱了`pay_notice_wk`,當A收到通知後,接着B的支付通知也發佈了,這時渠道收不到第二次消息發佈。由於同一個頻道收到消息後,訂閱自動取消,也就是訂閱是一次性的。

因此咱們訂閱的訂單支付狀態的頻道就得惟一,一個訂單一個頻道,咱們能夠在頻道上加上訂單號`pay_notice_wk`+orderNo保證頻道惟一。這樣咱們能夠把頻道號在支付時當作參數一併傳過去,支付平臺處理完就能夠用此頻道發佈消息給咱們了。(實際大多接口用回調通知,由於用Redis發佈訂閱限制條件苛刻,系統間必須共用一套Redis)

二、任務通知

 

好比經過跑批系統通知應用系統作一些事(跑批系統沒法拿到用戶數據,且應用系統又不能作定時任務的狀況下)。

如天天凌晨3點提早加載一些用戶的用戶數據到Redis,應用系統不能作定時任務,能夠經過系統公共的Redis來由跑批系統發佈任務給應用系統,應用系統收到指令,去作相應的操做。

這裏須要注意的是在線上集羣部署的狀況下,全部服務實例都會收到通知,都要作一樣的操做嗎?徹底不必。能夠用Redis實現鎖機制,其中一臺實例拿到鎖後執行任務。另外若是任務比較耗時,能夠不用鎖,能夠考慮一下任務分片執行。固然這不在本文的討論範疇,這裏不在贅述。

 

三、參數刷新加載

 

衆所周知,咱們用Redis無非就是將系統中不怎麼變的、查詢又比較頻繁的數據緩存起來,例如咱們系統首頁的輪播圖啊,頁面的動態連接啊,一些系統參數啊,公共數據啊都加載到Redis,而後有個後臺管理系統去配置修改這些數據。

 

打個比方咱們首頁的輪播圖要再增長一個圖,那咱們就在後管系統加上,加上就完事了嗎?固然沒有,由於Redis裏仍是老數據。那你會說不是有過時時間嗎?是的,但有的過時時間設置的較長如24小時而且咱們想當即生效怎麼辦?這時候咱們就能夠利用Redis的發佈訂閱機制來實現數據的實時刷新。當咱們修改完數據後,點擊刷新按鈕,經過發佈訂閱機制,訂閱者接收到消息後調用從新加載的方法便可。

 


關於發佈訂閱的JAVA版源碼實現,因爲篇幅緣由將會在下篇文章分享

[end]

文章首發於公衆號@編程大道

相關文章
相關標籤/搜索