1. 程式人生 > 其它 >分散式鎖的一點看法

分散式鎖的一點看法

技術標籤: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的系統必須要考慮的問題。