基於redis的分佈式鎖二種應用場景

“分佈式鎖”是用來解決分佈式應用中“併發衝突”的一種常用手段,實現方式一般有基於zookeeper及基於redis二種。具體到業務場景中,我們要考慮二種情況:

一、搶不到鎖的請求,允許丟棄(即:忽略)

比如:一些不是很重要的場景,比如“監控數據持續上報”,某一篇文章的“已讀/未讀”標識位更新,對於同一個id,如果併發的請求同時到達,只要有一個請求處理成功,就算成功。

用活動圖表示如下:

基於redis的分佈式鎖二種應用場景

二、併發請求,不論哪一條都必須要處理的場景(即:不允許丟數據)

比如:一個訂單,客戶正在前臺修改地址,管理員在後臺同時修改備註。地址和備註字段的修改,都必須正確更新,這二個請求同時到達的話,如果不借助db的事務,很容易造成行鎖競爭,但用事務的話,db的性能顯然比不上redis輕量。

解決思路:A,B二個請求,誰先搶到分佈式鎖(假設A先搶到鎖),誰先處理,搶不到的那個(即:B),在一旁不停等待重試,重試期間一旦發現獲取鎖成功,即表示A已經處理完,把鎖釋放了。這時B就可以繼續處理了。

但有二點要注意:

a、需要設置等待重試的最長時間,否則如果A處理過程中有bug,一直卡死,或者未能正確釋放鎖,B就一直會等待重試,但是又永遠拿不到鎖。

b、等待最長時間,必須小於鎖的過期時間。否則,假設鎖2秒過期自動釋放,但是A還沒處理完(即:A的處理時間大於2秒),這時鎖會因爲redis key過期“提前”誤釋放,B重試時拿到鎖,造成A,B同時處理。(注:可能有同學會說,不設置鎖的過期時間,不就完了麼?理論上講,確實可以這麼做,但是如果業務代碼有bug,導致處理完後沒有unlock,或者根本忘記了unlock,分佈式鎖就會一直無法釋放。所以綜合考慮,給分佈式鎖加一個“保底”的過期時間,讓其始終有機會自動釋放,更爲靠譜)

用活動圖表示如下:

基於redis的分佈式鎖二種應用場景

用2個線程模擬併發場景,跑起來後,輸出如下:

基於redis的分佈式鎖二種應用場景

可以看到T2線程沒搶到鎖,直接拋出了預期的異常。

把44行的註釋打開,即:換成不允許丟數據的模式,再跑一下:

基於redis的分佈式鎖二種應用場景

可以看到,T1先搶到鎖,然後經過2秒的處理後,鎖釋放,這時T2重試拿到了鎖,繼續處理,最終釋放。

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