在處理分布式應用併發的時候,常常會使用鎖。
比如我們有個 num = 3, 應用對num操作基本實現去資料庫取值
取完值,在記憶體中,進行邏輯運算後重新賦值
存回資料庫
當多個應用同時對num操作的時候
比如 a和b 都對num進行操作
取值 a1 b1
賦值 b1 b3
在資料庫操作中,如果執行順序是
a1 a3 b1 b3
,那num
的值是正確的。如果執行順序是
a1 b1 a3 b3
,那麼num
值就會異常所以需要將 a1 b1 綁在一起執行,中間不能穿插其他操作。
setnx命令
當key 不存在時,為key設定乙個字串
設定成功,返回 1 。 設定失敗,返回 0
我們將這個key當做是乙個鎖的標誌
當redis中存在這個key,說明鎖在別人手上,反之不存在key的時候,我們設定這個key,搶到鎖。
然後我們執行一些邏輯操作,完成後,然後釋放鎖 就是刪除這個key
> setnx lock_codehole trueok.
..do something
>
del lock_codehole
(integer)
1
但是上面存在一些問題,就是一定要釋放鎖,如果因為一些原因沒有del
,就會造成死鎖
這個我們可以再此基礎上,設計可以給lock_codehole
加上乙個過期時間。
> setnx lock:codehole true
ok> expire lock:codehole 5..
. do something critical ...
>
del lock:codehole
(integer)
1
但是 在setnx
和expire
中間 也不能出現異常。
所以我們可以執行set lock:codehole true ex 5 nx
,合二為一。
redis2.8後,加入了這個命令,沒有加之前都是使用的第三方分布式鎖 library 。
所謂原子操作是指不會被執行緒排程機制打斷的操作;這種操作一旦開始,就一直執行到結束,中間不會有任何 context switch 執行緒切換。
知道了實現鎖的基本原理,並且加上了過期時間,還有問題。
就是如果我們的業務邏輯不能在過期時間內完成,那麼我們刪除鎖的操作,其實刪除的是其他程式的鎖。
為了解決這個問題,我們使用分布式鎖定時候,盡量不要處理耗時較長的業務
偶爾出現超時,我們需要人工干預,設定乙個隨機數。
釋放鎖時先匹配隨機值是否一致,然後再刪除 key
tag =
str(uuid.uuid4())
# 隨機值
if redis.
set(key, tag, nx=
true
, ex=5)
: do_something(
) redis.delifequals(key, tag)
# 假想的 delifequals 指令
# 檢視取出key的值 與 tag 是否相等,相等再刪除
但是還有遺留問題,就是雖然鎖的問題解決了,但是我們的業務邏輯已經執行,有些可能需要回滾(?),或者想辦法延長鎖的時間(?),還是其他辦法呢。
除了以上的簡單例項,還可以更複雜,比如鎖可以被多個程式同時持有,但可以設定上限n。
Redis(五)分布式鎖
1.分布式鎖是什麼 分布式鎖是控制分布式系統或不同系統之間共同訪問共享資源的一種鎖實現,如果不同的系統或同一系統的不同主機之間共享了某個資源時,往往通過互斥來防止彼此干擾。2.分布式設計目的 可以保證在分布式部署的應用集群中,同乙個方法在同一操作只能被一台機器上的乙個執行緒執行。3.設計要求 1 這...
redis2 分布式鎖
尚矽谷 陽哥 加鎖 stringredistemplate.opsforvalue setifabsent redis lock key,value setnx 釋放鎖 stringredistemplate.delete redis lock key 釋放鎖 stringredistemplate...
分布式鎖 3 分布式鎖租約續期
redis分布式鎖在加鎖的時候,我們一般都會給乙個鎖的過期時間 ttl 這是為了防止加鎖後client宕機,鎖無法被釋放的問題。但是所有這種姿勢的用法都會面臨同乙個問題,就是沒發保證client的執行時間一定小於鎖的ttl。雖然大多數程式設計師都會樂觀的認為這種情況不可能發生,但是各種異常情況都會導...