分散式鎖的一點看法
技術標籤:java
分散式鎖的主流方案
-
基於資料庫
- select for update。這個鎖理論上沒有超時能力,只能等客戶端斷開連線才行。所以實際上不能用於高併發&執行高耗時的場景。
- 另外一種方案是仿照redis,在資料庫裡insert行。並設定唯一索引。這其實和redis鎖的原理是一致的。
-
基於zookeeper
https://blog.csdn.net/define_us/article/details/79698940
zookeepr的鎖其實和資料庫是一樣的問題。如果有臨時節點的機器沒有正確處理監聽器邏輯。那麼,整個鎖就會被卡死。解決的辦法也和redis鎖一樣。(本質上zk的znode也是一個key-value格式嘛)。機器會迴圈遍歷,一旦發現自己的前序臨時節點的前序臨時節點已經刪除。就在本地計時。在超時後,直接將該節點刪除。喚醒本節點。但是zookeeper作為分散式鎖的最大問題,是它僅保證最終一致性。你不能假設每臺伺服器都能從zookeeper看到相同的狀態。 -
基於redis
https://blog.csdn.net/define_us/article/details/79698408
可以說,redis的鎖是唯一在大規模併發場景中可以使用的鎖。
資料庫和redis可以實現在不考慮超時的情況下實現嚴格的分散式鎖。因為他們本身就是單點。但是,如果考慮超時,這個問題就無解了。沒有一種考慮超時的分散式鎖能夠保證全域性唯一執行。
所以,一個簡單的辦法是,redis作為第一層,資料庫行鎖作為第二層。為了克服資料庫行鎖沒有超時時間的問題,
Spring事務提供了超時時間的配置
@Transactional(timeout=1)
但可惜,這個超時能力是spring計時器提供的。不是資料庫本身提供的。可能會存在比如說獲取行鎖後展開大規模的GC,整個JVM被卡住。(但是資料庫session不會超時,因為為了配合資料庫連線池,一般資料庫session超時配置到很大)。讓然會造成整個系統卡住。
https://qingmiaogu.blog.csdn.net/article/details/80108576
其實,這樣的問題出現的概率很低才對。第一層的redis鎖已經把壓力降下來了,第二層資料庫操作卻意外超時了。這簡直是不可接受的。所以,我們需要努力在程式碼和系統配置容量上,避免上述出現的問題。這也其實是所有使用select for update的系統必須要考慮的問題。