基于redis的分布式锁
概述
在之前, 我也使用redis做過分布式鎖, 當時的做法是這樣的:
當時覺得貌似沒什么問題. 是我太天真了, 今天突然想到, 恩, 有問題.
問題
1.如果在第一步之后, 程序崩了, 沒有給鎖設置過期時間, 導致所有后續操作都無法正常獲取到鎖. 怎么破?
2.在A成功上鎖后, 因為IO阻塞等原因, 執行時間有點長, 鎖已經過期了, 這時B過來成功上鎖, A在釋放鎖的時候釋放的就是B的鎖.
3.redis突然掛了. 如果redis突然掛了, 怎么辦? 當然, 可以增加redis節點, 主節點掛了, 從節點立刻補上. 但是, 主節點的數據同步到從節點也是需要時間的吧. 假設一個場景:
這個時候, 分布式鎖就失效了.
解決
那么有沒有辦法解決上面的問題呢? 我到萬能的谷歌上找了一下, 恩, 真的有.
上面的問題一個一個解決.
問題一
如何避免沒有給鎖設置過期時間的問題?
其實看看就知道了, 問題出在設置key和設置value分成兩條命令執行, 所以導致如果在 setnx命令執行過后, 程序崩潰, expire命令沒有正常執行, 將其合并為一條命令就好啦.
set key value NX PX 5000
其中NX表示存在則不設置, PX表示過期時間.
如此, 至少可以保證不會出現沒有過期時間的鎖了
問題二
如何避免A釋放了B的鎖.
如何避免釋放了其他人的鎖呢? 換個問題, 如何保證這個鎖是你加的呢? so easy, 加鎖的時候, 講value值設置成一個只有我知道的隨機數字, 釋放的時候看看值是不是我的就行了.
如此在釋放的時候需要兩步操作:
當然, 為了保證釋放鎖操作的原子性, 這兩步操作最好也能合并為一步操作. 那redis如何實現值是否相同的判斷呢? Lua腳本.
簡單介紹一下
eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 argv1 argv2 # 看懂了吧, 哈哈 # eval 是redis內置的命令 # 第一個參數是運行的腳本邏輯 # 第二個參數表示后面有幾個key # 第五個參數開始就是附加參數, 在腳本邏輯中使用的所以, 腳本內容如下:
if redis.call("get",KEYS[1]) == ARGV[1] thenreturn redis.call("del",KEYS[1]) elsereturn 0 end如此, 至少可以保證不會出現A釋放了B鎖的情況了
問題三
如何保證在主節點掛掉的時候, 從節點接替后, 不會重復獲得鎖?
官網上提供了一個方法, 從多個redis實例同時獲取鎖. 因為我沒看太明白, 之后看懂了在說吧. 過…
其實, 如果不是處理金錢這種不容出錯的業務, 這種小概率事件個人覺得還是可以容忍的.
總結
最終, 在redis單機下實現的分布式鎖操作如下:
# 獲取分布式鎖,過期時間可調 set lock_key random_value NX PX 5000 # ...do something # 釋放分布式鎖 eval "if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end" 1 lock_key random_value總結
以上是生活随笔為你收集整理的基于redis的分布式锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 图片饱和度_摄影后期完全调色指南(三):
- 下一篇: 计算机网络-信道复用技术