第一:基於資料庫
第二:基於快取
第三:基於zookeeper
要實現分布式鎖,最簡單的方式可能就是直接建立一張鎖表,然後通過操作該表中的資料來實現了。
當我們要鎖住某個方法或資源時,我們就在該表中增加一條記錄,想要釋放鎖的時候就刪除這條記錄。
create table `methodlock` (
`id` int(11) not null auto_increment comment '主鍵',
`method_name` varchar(64) not null default '' comment '鎖定的方法名',
`desc` varchar(1024) not null default '備註資訊',
`update_time` timestamp not null default current_timestamp on update current_timestamp comment '儲存資料時間,自動生成',
primary key (`id`),
unique key `uidx_method_name` (`method_name `) using btree
) engine=innodb default charset=utf8 comment='鎖定中的方法';
當我們想要鎖住某個方法時,執行以下sql:
insert into methodlock(method_name,desc) values (『method_name』,『desc』);
方法執行完成後,釋放鎖:
delete from methodlock where method_name ='method_name'
上述方法看起來原理很簡單,但是會存在一些問題?
這把鎖沒有失效是時間,一旦解鎖失敗,就會導致鎖一直在資料庫裡邊,導致業務系統不可用。
這把鎖是非阻塞的,不管成功還是失敗都是立即返回。這把鎖是非阻塞的,不管成功還是失敗都是立即返回的。
這個鎖是非重入的。
要解決上述問題,其實也簡單,可通過下邊的操作來避免上述問題。
這把鎖沒有失效是時間?有兩個方案:
使用spring的巢狀事務來操作。使用分布式鎖的時候就起事務,業務**再起乙個事務,使用的傳播行為是required new,可以在上層事務回滾後不影響內層事務;
乙個定時任務,每隔一定時間把資料庫中的超時資料清理一遍。
非阻塞的?
搞乙個while迴圈,不斷的往資料庫裡邊插入資料,直到插入成功為止或者到期為止。
這個鎖是非重入的?
在資料行記錄中,記錄下執行緒的資訊,當獲取鎖的時候,先判斷執行緒是否是當前執行緒,是的話,返回成功,不是的話,返回失敗。
相對於基於資料庫實現分布式鎖的方案來說,基於快取的實現在效能上能有很大的優勢;
目前成熟的快取資料庫有很多,redis、memcached以及阿里能內中快取中介軟體tair等
實現的原理是加鎖時,利用往快取裡邊寫入一條資料,其中某乙個欄位是唯一的。
鎖釋放時手動刪除這個記錄。
這個方案也存在一些問題:
這把鎖是非重入鎖
這把鎖是非阻塞的。
非重入鎖?
和資料庫實現分布式鎖類似,其實問題還是乙個問題,解決方案也是類似的。
在儲存的資料記錄中查詢執行緒資訊,如果和當前執行緒是一致的就直接獲取鎖,不一致就獲取鎖失敗。
非阻塞的?
同樣的加乙個迴圈,直到加鎖成為未知。
可以基於zk的臨時節點做分布式鎖。
大致思想就是客戶端在對某個方法加鎖時,都會在相應的方法節點下加乙個臨時有序節點,在客戶端執行完業務,會釋放鏈結,臨時節點自然刪除。判斷是否獲取鎖的邏輯是判斷當前臨時節點序號是否是做小的,如果是則獲取到了鎖。
分布式 分布式鎖
本質是利用redis的setnx 方法的特性來加鎖,setnx 即key不存在則設定key,否則直接返回false,要求在分布式系統中使用同乙個redis服務,以下提供兩種解決方案 1 直接使用redistemplate 這其實並不能完全保證高併發下的安全問題,因為可能在鎖過期之後該執行緒尚未執行完...
分布式專題 分布式鎖
在傳統的單體應用架構中,遇到併發安全性問題時我們可以通過同步鎖synchronized,同步 塊,reentrantlock等方式都可以解決,但隨著業務的發展,單體應用架構不能滿足龐大的使用者請求量,於是分布式系統應用而生,在分布式系統中,由於每個系統都執行在不同的伺服器上,有著不同的jvm,所以j...
分布式鎖 使用Redis實現分布式鎖
關於分布式鎖的實現,我的前一篇文章講解了如何使用zookeeper實現分布式鎖。關於分布式鎖的背景此處不再做贅述,我們直接討論下如何使用redis實現分布式鎖。關於redis,筆主不打算做長篇大論的介紹,只介紹下redis優秀的特性。支援豐富的資料型別,如string list map set zs...