分布式锁闲谈
分布式鎖閑談
前言
服務器單機情況下,要鎖住某個資源,我們一般用到的是synchronized,lock等鎖,這是java提供的,也確實能很有效的鎖住資源。
但是在服務器集群的情況下,上面這些單機鎖就不起作用了,你能鎖住這臺機器,但剩下的機器都沒鎖,就沒有意義。
所以,一般解決這種問題,我們都用分布式鎖。
分布式鎖原理
分布式鎖,主要原理就是新增了一個第三方存儲介質,代替以前的synchronized。
假設服務器A對某個資源加鎖后,就在這個第三方介質中記錄,然后其他服務器再訪問該資源的時候,就能知道這個資源被鎖住了,效果就達到了。
所以也可以說,這個第三方資源,也可以理解成將服務器集群強行變成了一個單機服務器了。
一般情況下,能擔當這個第三方介質的,有以下三種。
1.數據庫
2.redis
3.zookeeper
1.數據庫
不管集群有幾個服務器,都會操作一張表
所以,想要加鎖,只需在數據庫中插入一條數據即可,記錄這個資源的唯一標識,狀態為已加鎖。
再有加鎖的請求,一查數據庫已經加鎖了,就是沒有獲取到鎖。
一般基于數據庫的分布式鎖,都會考慮以下幾個問題
鎖的失效時間(一般做法就是job定時掃,刪掉過期的鎖,但多久才算過期,是一個很值得仔細研究的問題,一般都是因具體業務來定)
數據庫的可靠性(這個倒不是主要問題,一般可以通過搭建集群等方式解決)
數據庫的效率問題(畢竟數據庫是讀磁盤,肯定沒有讀內存快)
2.redis
這個應該是最常見的,redis分布式鎖。
setNx方法估計很多人都用過,不多說了,set if not exist
舊版本的redis,加鎖和設置過期時間,但這樣是有問題的,比如加鎖了,但沒有來得及設置過期時間,服務掛了,那么這個鎖就死鎖了
新版redis,相當于將這兩步合成一個方法了,支持多參數,這就感覺很完美啊,不過我沒用過,可以試試,應該沒問題。
一般基于redis的分布式鎖,會考慮以下問題:
鎖的失效問題(和數據庫分布式鎖一樣,失效時間設置多少算最優,沒有答案,只能job異步掃,一樣的問題,所以不能算是一個優雅的解決方案)
鎖是非阻塞的 (成功失敗都會立即返回,這個要看業務怎么操作了,也可以在業務上手動阻塞住,這不是問題,但要知道)
3.zookeeper
大數據高并發,一般用這個
使用臨時有序節點,服務器A的方法加鎖就在對應方法節點上創建一個臨時有序節點,算是獲得鎖,因為第一個創建的,序號最小,所以后面再有其他服務器想要加鎖時,一查自己的節點的序號不是最小,所以就算沒有獲得鎖。
因為zookeeper的臨時有序節點,當加鎖的這個線程斷掉后,這個節點也自動消失,那么鎖也就自動釋放了,是不是感覺特別合適做分布式鎖,上面兩個關于鎖的失效問題,用zookeeper得到了優雅的解決
一般需要注意的是:
zookeeper相對復雜(zookeeper算是比較重量級的,甚至有些小項目都不會用到zookeeper,所以也沒有必要為了一個簡單的分布式鎖的問題,強行使用zookeeper)
性能問題(一般和redis比性能,都是弟弟)
總結
在性能方面,redis > zookeeper > 數據庫
在實現的復雜度方面,zookeeper > redis > 數據庫
對于新手而言,數據庫 > redis > zookeeper
可靠性方面,zookeeper > redis > 數據庫
所以,一般項目用redis分布式鎖就可以了,
如果對可靠性要求很高,那么建議考慮zookeeper分布式鎖,
幾乎很少用數據庫分布式鎖,主要還是性能問題。
補充
其實分布式鎖就是一個集群環境如何共享資源的問題,我們看問題的角度不應該僅僅停留在分布式鎖這里。很多問題的解決方案,其實都是大同小異的。
比如shiro的集群session共享,一般做法也是放在redis中,其實和這個redis的分布式鎖原理一樣。
還有很多類似場景,歡迎評論補充。
總結
- 上一篇: CSS串联和后代选择器
- 下一篇: [网络]------长连接和短连接