1. 程式人生 > >高併發架構系列:Redis併發競爭key的解決方案詳解

高併發架構系列:Redis併發競爭key的解決方案詳解

需求由來

1.Redis高併發的問題

Redis快取的高效能有目共睹,應用的場景也是非常廣泛,但是在高併發的場景下,也會出現問題:快取擊穿、快取雪崩、快取和資料一致性,以及今天要談到的快取併發競爭。

這裡的併發指的是多個redis的client同時set key引起的併發問題。

2.出現併發設定Key的原因

Redis是一種單執行緒機制的nosql資料庫,基於key-value,資料可持久化落盤。由於單執行緒所以Redis本身並沒有鎖的概念,多個客戶端連線並不存在競爭關係,但是利用jedis等客戶端對Redis進行併發訪問時會出現問題。

比如:同時有多個子系統去set一個key。這個時候要注意什麼呢?

3.舉一個例子

多客戶端同時併發寫一個key,一個key的值是1,本來按順序修改為2,3,4,最後是4,但是順序變成了4,3,2,最後變成了2。
在這裡插入圖片描述

如何解決redis的併發競爭key問題呢?下面給到2個Redis併發競爭的解決方案。

第一種方案:分散式鎖+時間戳

1.整體技術方案

這種情況,主要是準備一個分散式鎖,大家去搶鎖,搶到鎖就做set操作。

加鎖的目的實際上就是把並行讀寫改成序列讀寫的方式,從而來避免資源競爭。

2.Redis分散式鎖的實現

主要用到的redis函式是setnx()

用SETNX實現分散式鎖

利用SETNX非常簡單地實現分散式鎖。例如:某客戶端要獲得一個名字youzhi的鎖,客戶端使用下面的命令進行獲取:

SETNX lock.youzhi<current Unix time + lock timeout + 1>

如返回1,則該客戶端獲得鎖,把lock.youzhi的鍵值設定為時間值表示該鍵已被鎖定,該客戶端最後可以通過DEL lock.foo來釋放該鎖。
如返回0,表明該鎖已被其他客戶端取得,這時我們可以先返回或進行重試等對方完成或等待鎖超時。

3.時間戳

由於上面舉的例子,要求key的操作需要順序執行,所以需要儲存一個時間戳判斷set順序。

系統A key 1 {ValueA 7:00}

系統B key 1 { ValueB 7:05}

假設系統B先搶到鎖,將key1設定為{ValueB 7:05}。接下來系統A搶到鎖,發現自己的key1的時間戳早於快取中的時間戳(7:00<7:05),那就不做set操作了。

4.什麼是分散式鎖

因為傳統的加鎖的做法(如java的synchronized和Lock)這裡沒用,只適合單點。因為這是分散式環境,需要的是分散式鎖。

當然,分散式鎖可以基於很多種方式實現,比如zookeeper、redis等,不管哪種方式實現,基本原理是不變的:用一個狀態值表示鎖,對鎖的佔用和釋放通過狀態值來標識。

第二種方案:利用訊息佇列

在併發量過大的情況下,可以通過訊息中介軟體進行處理,把並行讀寫進行序列化。

把Redis.set操作放在佇列中使其序列化,必須的一個一個執行。

這種方式在一些高併發的場景中算是一種通用的解決方案。

以上就是Redis併發競爭key技術方案詳解,相關的Redis高併發問題具體還可以參考:高併發架構系列:如何解決Redis雪崩、穿透、併發等5大難題

我是mikechen,每日分享bat架構+面試+技術乾貨!堅持原創不易,覺得不錯點贊支援,送你【分散式架構23期學習資料合集】,加QQ 649449578領取資料、深度交流,驗證通關暗號【架構】。
在這裡插入圖片描述