Redis事務和併發控制

什麼是Redis事務?

Redis事務不保證原子性, 即事務中的某個命令執行失敗, 事務不會回滾, 且後續命令會繼續執行. 這樣一來, Redis事務的功能就和腳本差不多, 都是將命令打包, Redis事務能做的事, 腳本也能做, 而且腳本速度更快.

(1) Redis事務相關的命令

  • MULTI
    開啓一個事務, 後續的命令都會添加到一個隊列中, 等待EXEC命令.
  • EXEC
    觸發並執行事務中的所有命令.
  • DISCARD
    清空事務隊列.

(2) 實例一

127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> incrby num 2
QUEUED
127.0.0.1:6379> exec
1) (integer) 2
2) (integer) 4
127.0.0.1:6379> get num
"4"

(3) 實例二

127.0.0.1:6379> set num 1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr num
QUEUED
127.0.0.1:6379> discard
OK
127.0.0.1:6379> get num
"1"

Redis併發控制

redis本身是沒有鎖的概念的, 但由於redis是單進程單線程的, 所以redis內部也不會出現併發衝突. 雖然redis內部不會出現併發衝突, 但這並不代表在業務場景下使用redis, 也不會出現併發衝突, 比如以下業務場景:

  • 多個客戶端併發地寫同一個key, 且寫命令的執行順序對結果會有影響
  • 多個客戶端併發地讀同一個key, 如果滿足條件就修改值後寫回去.

下面我們就來了解在業務場景下使用redis的併發衝突該如何解決.

樂觀鎖

redis樂觀鎖, 即CAS(check-and-set)機制, 客戶端A在修改key之前先監控key, 如果key被其他客戶端修改, 那麼客戶端A的修改就會失敗, 返回 nil. 注意: 客戶端A的修改要與事務一起使用.

  • WATCH
    監控key是否被其他客戶端修改, 如果被修改則返回nil.
  • UNWATCH
    取消對key的監控.

實例如下:

127.0.0.1:6379> watch mykey
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set mykey 789
QUEUED
127.0.0.1:6379> exec
(nil)

分佈式鎖

客戶端在讀寫redis之前必須先從redis獲取鎖, 只有獲取到鎖的客戶端才能讀寫redis.

爲什麼不能簡單的使用synchronized互斥鎖? 因爲synchronized只對單機部署有用, 而我們的應用是多機部署的.

(1) 方案一

a. 獲取鎖

SET my_lock 隨機值 PX 5000 NX

PX是設置過期時間, 單位毫秒. NX是僅當key不存在時才設置值.

b. 刪除鎖

只有提供的value值相同才能刪除鎖, 因爲我們不能讓客戶端刪除別人的鎖. 因爲涉及到條件判斷, 爲了保證事務特性, 必須使用Lua腳本.

if redis.call("get",KEYS[1]) == ARGV[1] then
	return redis.call("del", KEYS[1])
else
    return 0
end

c. 實例

//1. 獲取鎖
127.0.0.1:6379> SET my_lock 123456 PX 5000 NX
OK

//2. 使用lua腳本刪除鎖
[root@master ~]# redis-cli --eval delKey.lua my_lock , 123456
(integer) 1

//3. 查看key
127.0.0.1:6379> get my_lock
(nil)

(2) 方案二

上面方案一的分佈式鎖有個問題, 如果在key同步到子節點之前主節點宕機了, 就會導致鎖丟失. 爲此redis提供了在集羣架構下的分佈式鎖, 即RedLock算法.

  • 獲取當前時間戳, 單位是毫秒.
  • 跟上面類似, 輪流嘗試在每個master節點上創建鎖, 過期時間較短, 一般就幾十毫秒.
  • 嘗試在大多數節點上建立一個鎖, 比如5個節點就要求是3個節點(n/2 + 1).
  • 客戶端計算建立好鎖的時間, 如果建立鎖的時間小於超時時間, 就算建立成功了
  • 要是鎖建立失敗了,那麼就依次刪除這個鎖
  • 只要別人建立了一把分佈式鎖,你就得不斷輪詢去嘗試獲取鎖

這種RedLock算法在業界還存在爭議, 我們只需要瞭解下, 所以真正的方案二應該是使用ZooKeeper分佈式鎖.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章