'漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能'

Redis 數據結構 數據庫 Lua 設計 沙茶敏碎碎念 2019-08-17
"

我們經常在網上看到某個活動,如果活動還沒開始 ,我們經常可以到點提醒我,那麼,到點提醒這個功能,該如何實現呢?


"

我們經常在網上看到某個活動,如果活動還沒開始 ,我們經常可以到點提醒我,那麼,到點提醒這個功能,該如何實現呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


最簡單的做法,就是每次用戶訂閱的時候,插入一條數據到數據庫裡面,然後找一臺機器,開啟一個進程,定時地從數據庫裡面撈數據,撈取到數據之後再調用第三方push接口推送數據。這個設計非常簡單,但是存在什麼問題呢?那便是存在單點問題,如果負責讀取數據的機器掛了,或者那個時間點正在發佈,豈不是用戶就收不到推送了?

如果我們使用多臺機器,又有可能存在併發問題,例如A機器跟B機器同時讀到用戶甲需要發送提醒,用戶就有可能同時收到兩條提醒。為了避免這個問題,我們可能需要使用Redis實現一個分佈式鎖。那麼我們有沒有其他方案呢?


"

我們經常在網上看到某個活動,如果活動還沒開始 ,我們經常可以到點提醒我,那麼,到點提醒這個功能,該如何實現呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


最簡單的做法,就是每次用戶訂閱的時候,插入一條數據到數據庫裡面,然後找一臺機器,開啟一個進程,定時地從數據庫裡面撈數據,撈取到數據之後再調用第三方push接口推送數據。這個設計非常簡單,但是存在什麼問題呢?那便是存在單點問題,如果負責讀取數據的機器掛了,或者那個時間點正在發佈,豈不是用戶就收不到推送了?

如果我們使用多臺機器,又有可能存在併發問題,例如A機器跟B機器同時讀到用戶甲需要發送提醒,用戶就有可能同時收到兩條提醒。為了避免這個問題,我們可能需要使用Redis實現一個分佈式鎖。那麼我們有沒有其他方案呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


今天我們來分享一個使用Redis實現的延遲隊列,在此之前,我們分享過Redis的基本數據結構,我們都知道,Redis有5種基本數據結構,字符串、隊列、哈希、集合與有序集合。今天我們就要用有序集合,來實現一個延遲隊列的功能。


"

我們經常在網上看到某個活動,如果活動還沒開始 ,我們經常可以到點提醒我,那麼,到點提醒這個功能,該如何實現呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


最簡單的做法,就是每次用戶訂閱的時候,插入一條數據到數據庫裡面,然後找一臺機器,開啟一個進程,定時地從數據庫裡面撈數據,撈取到數據之後再調用第三方push接口推送數據。這個設計非常簡單,但是存在什麼問題呢?那便是存在單點問題,如果負責讀取數據的機器掛了,或者那個時間點正在發佈,豈不是用戶就收不到推送了?

如果我們使用多臺機器,又有可能存在併發問題,例如A機器跟B機器同時讀到用戶甲需要發送提醒,用戶就有可能同時收到兩條提醒。為了避免這個問題,我們可能需要使用Redis實現一個分佈式鎖。那麼我們有沒有其他方案呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


今天我們來分享一個使用Redis實現的延遲隊列,在此之前,我們分享過Redis的基本數據結構,我們都知道,Redis有5種基本數據結構,字符串、隊列、哈希、集合與有序集合。今天我們就要用有序集合,來實現一個延遲隊列的功能。


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


我們都知道,有序集合的內部是一個跳錶+哈希,跳錶的一個特點是能夠保證數據的有消息,所以我們就能把任務的執行時間按照從小到大的時間排序,隊首的元素就是需要最早執行的任務。這裡我們簡單地學習幾個Redis的命令,分別是添加ZADD,移除ZREM,與查詢ZRANGEBYSCORE。

#ZADD 集合名 分數 關鍵字

當有用戶點擊訂閱提醒我的時候,我們就把提醒的時間作為分數,把用戶的id+訂閱內容的id作為key,插入到我們定義的一個集合裡面。如果用戶取消訂閱提醒,那麼,我們就把對應的id刪除

#ZRANGEBYSCORE 集合名 最小值 最大值

每一秒鐘,我們都可以用這個去查詢當前需要執行的任務有哪一些,例如當前的時間戳為1558193281,那麼我們只要執行命令ZRANGEBYSCORE 集合名 0 1558193281,就能查詢到在此之前有多少任務滿足條件。

#ZREM 集合名 內容

當我們查詢到有哪些任務需要執行的時候,我們需要將他們移除,這樣子才不會被其他任務所執行。這個命令就是用來移除對應的任務。

這裡,可能有同學就會想到,如果多臺機器獲取到同一個任務,那豈不是會衝突麼?好在我們可以使用lua script幫我們把查詢跟刪除的命令變成再服務端的一次原子操作。只要簡單的幾個命令,我們就能夠實現一個延遲隊列。剩下的時間,我們可以用來研究怎麼找對象了。

"

我們經常在網上看到某個活動,如果活動還沒開始 ,我們經常可以到點提醒我,那麼,到點提醒這個功能,該如何實現呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


最簡單的做法,就是每次用戶訂閱的時候,插入一條數據到數據庫裡面,然後找一臺機器,開啟一個進程,定時地從數據庫裡面撈數據,撈取到數據之後再調用第三方push接口推送數據。這個設計非常簡單,但是存在什麼問題呢?那便是存在單點問題,如果負責讀取數據的機器掛了,或者那個時間點正在發佈,豈不是用戶就收不到推送了?

如果我們使用多臺機器,又有可能存在併發問題,例如A機器跟B機器同時讀到用戶甲需要發送提醒,用戶就有可能同時收到兩條提醒。為了避免這個問題,我們可能需要使用Redis實現一個分佈式鎖。那麼我們有沒有其他方案呢?


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


今天我們來分享一個使用Redis實現的延遲隊列,在此之前,我們分享過Redis的基本數據結構,我們都知道,Redis有5種基本數據結構,字符串、隊列、哈希、集合與有序集合。今天我們就要用有序集合,來實現一個延遲隊列的功能。


漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能


我們都知道,有序集合的內部是一個跳錶+哈希,跳錶的一個特點是能夠保證數據的有消息,所以我們就能把任務的執行時間按照從小到大的時間排序,隊首的元素就是需要最早執行的任務。這裡我們簡單地學習幾個Redis的命令,分別是添加ZADD,移除ZREM,與查詢ZRANGEBYSCORE。

#ZADD 集合名 分數 關鍵字

當有用戶點擊訂閱提醒我的時候,我們就把提醒的時間作為分數,把用戶的id+訂閱內容的id作為key,插入到我們定義的一個集合裡面。如果用戶取消訂閱提醒,那麼,我們就把對應的id刪除

#ZRANGEBYSCORE 集合名 最小值 最大值

每一秒鐘,我們都可以用這個去查詢當前需要執行的任務有哪一些,例如當前的時間戳為1558193281,那麼我們只要執行命令ZRANGEBYSCORE 集合名 0 1558193281,就能查詢到在此之前有多少任務滿足條件。

#ZREM 集合名 內容

當我們查詢到有哪些任務需要執行的時候,我們需要將他們移除,這樣子才不會被其他任務所執行。這個命令就是用來移除對應的任務。

這裡,可能有同學就會想到,如果多臺機器獲取到同一個任務,那豈不是會衝突麼?好在我們可以使用lua script幫我們把查詢跟刪除的命令變成再服務端的一次原子操作。只要簡單的幾個命令,我們就能夠實現一個延遲隊列。剩下的時間,我們可以用來研究怎麼找對象了。

漲姿勢了,除了緩存跟分佈式鎖,Redis還能實現這個功能

如果細心的同學機會發現,用Redis實現的延遲隊列,並不能保證可用性100%,有可能會丟消息。這裡的有如下這些原因:

1.redis主備之間可能存在一致性問題,如果部署redis的主機掛了可能會丟數據。

2.在機器取到任務的時候,就把任務刪除了,如果這個時候死機或者發送失敗,也會丟消息

如果我們要保證更高的可用性,我們可以使用延遲隊列,常見的有RMQ或者卡夫卡,都有提供更高一致性,更高可用的延遲消息。每次用戶訂閱一個提醒的時候,往隊列裡面添加一個任務,並且寫入對應的延遲時間。當然,越是複雜的方案,開發起來就越複雜,至於要選擇複雜的方案還是簡單的方案,那就要看業務的重要程度跟大家的取捨了。

今天的介紹我們就講到這裡,有沒有學習到Redis新的姿勢呢,後面我們再繼續將Redis的一些命令與應用。如果你有興趣,歡迎關注我,主講算法相關的,近期還準備了一些AI相關的知識,整理後會和大家繼續分享。大家的支持是我繼續嘮嗑的動力。(同名公眾號:沙茶敏碎碎念)

"

相關推薦

推薦中...