從構建分佈式秒殺系統聊聊分佈式鎖

摘要: 前言 最近懶成一坨屎,學不動系列一波接一波,大多還都是底層原理相關的。上週末抽時間重讀了周志明大溼的 JVM 高效併發部分,每讀一遍都有不一樣的感悟。路漫漫,藉此,把前段時間搞着玩的秒殺案例中的分佈式鎖深刻了解一下。

clipboard.png

前言

最近懶成一坨屎,學不動系列一波接一波,大多還都是底層原理相關的。上週末抽時間重讀了周志明大溼的 JVM 高效併發部分,每讀一遍都有不一樣的感悟。路漫漫,藉此,把前段時間搞着玩的秒殺案例中的分佈式鎖深刻了解一下。算法

案例介紹

在嘗試瞭解分佈式鎖以前,你們能夠想象一下,什麼場景下會使用分佈式鎖?數據庫

clipboard.png

單機應用架構中,秒殺案例使用ReentrantLcok或者synchronized來達到秒殺商品互斥的目的。然而在分佈式系統中,會存在多臺機器並行去實現同一個功能。也就是說,在多進程中,若是還使用以上JDK提供的進程鎖,來併發訪問數據庫資源就可能會出現商品超賣的狀況。所以,須要咱們來實現本身的分佈式鎖。緩存

實現一個分佈式鎖應該具有的特性:網絡

▪ 高可用、高性能的獲取鎖與釋放鎖session

▪ 在分佈式系統環境下,一個方法或者變量同一時間只能被一個線程操做架構

▪ 具有鎖失效機制,網絡中斷或宕機沒法釋放鎖時,鎖必須被刪除,防止死鎖併發

▪ 具有阻塞鎖特性,即沒有獲取到鎖,則繼續等待獲取鎖分佈式

▪ 具有非阻塞鎖特性,即沒有獲取到鎖,則直接返回獲取鎖失敗高併發

▪ 具有可重入特性,一個線程中能夠屢次獲取同一把鎖,好比一個線程在執行一個帶鎖的方法,該方法中又調用了另外一個須要相同鎖的方法,則該線程能夠直接執行調用的方法,而無需從新得到鎖工具

在以前的秒殺案例中,咱們曾介紹過關於分佈式鎖幾種實現方式:

▪ 基於數據庫實現分佈式鎖

▪ 基於 Redis 實現分佈式鎖

▪ 基於 Zookeeper 實現分佈式鎖

前兩種對於分佈式生產環境來講並非特別推薦,高併發下數據庫鎖性能太差,Redis在鎖時間限制和緩存一致性存在必定問題。這裏咱們重點介紹一下 Zookeeper 如何實現分佈式鎖。

實現原理
ZooKeeper是一個分佈式的,開放源碼的分佈式應用程序協調服務,它內部是一個分層的文件系統目錄樹結構,規定同一個目錄下只能存在惟一文件名。

clipboard.png

數據模型

▪ PERSISTENT 持久化節點,節點建立後,不會由於會話失效而消失

▪ EPHEMERAL 臨時節點, 客戶端session超時此類節點就會被自動刪除

▪ EPHEMERAL_SEQUENTIAL 臨時自動編號節點

▪ PERSISTENT_SEQUENTIAL 順序自動編號持久化節點,這種節點會根據當前已存在的節點數自動加 1

監視器(watcher)

當建立一個節點時,能夠註冊一個該節點的監視器,當節點狀態發生改變時,watch被觸發時,ZooKeeper將會向客戶端發送且僅發送一條通知,由於watch只能被觸發一次。

根據zookeeper的這些特性,咱們來看看如何利用這些特性來實現分佈式鎖:

▪ 建立一個鎖目錄lock

▪ 線程A獲取鎖會在lock目錄下,建立臨時順序節點

▪ 獲取鎖目錄下全部的子節點,而後獲取比本身小的兄弟節點,若是不存在,則說明當前線程順序號最小,得到鎖

▪ 線程B建立臨時節點並獲取全部兄弟節點,判斷本身不是最小節點,設置監聽(watcher)比本身次小的節點(只關注比本身次小的節點是爲了防止發生「羊羣效應」)

▪ 線程A處理完,刪除本身的節點,線程B監聽到變動事件,判斷本身是最小的節點,得到鎖

代碼分析
儘管ZooKeeper已經封裝好複雜易出錯的關鍵服務,將簡單易用的接口和性能高效、功能穩定的系統提供給用戶。可是若是讓一個普通開發者去手擼一個分佈式鎖仍是比較困難的,在秒殺案例中咱們直接使用 Apache 開源的curator 開實現 Zookeeper 分佈式鎖。

這裏咱們使用如下版本,截止目前最新版4.0.1:

clipboard.png

首先,咱們看下InterProcessLock接口中的幾個方法:

clipboard.png

獲取鎖:

clipboard.png

clipboard.png

Zookeeper獲取鎖實現:

clipboard.png

clipboard.png

釋放鎖:

clipboard.png

測試案例

爲了更好的理解其原理和代碼分析中獲取鎖的過程,這裏咱們實現一個簡單的Demo:

clipboard.png

這裏咱們開啓5個線程,每一個線程獲取鎖的最大等待時間爲5秒,爲了模擬具體業務場景,方法中設置4秒等待時間。開始執行main方法,經過ZooInspector監控/curator/lock下的節點以下圖:

clipboard.png

對,沒錯,設置4秒的業務處理時長就是爲了觀察生成了幾個順序節點。果真如案例中所述,每一個線程都會生成一個節點而且仍是有序的。

觀察控制檯,咱們會發現只有兩個線程獲取鎖成功,另外三個線程超時獲取鎖失敗會自動刪除節點。線程執行完畢咱們刷新一下/curator/lock節點,發現剛纔建立的五個子節點已經不存在了。

小結

經過分析第三方開源工具實現的分佈式鎖方式,收穫仍是滿滿的。學習自己就是一個由淺入深的過程,從如何調用API,到理解其代碼邏輯實現,想要更深刻能夠去挖掘Zookeeper的核心算法ZAB協議。

最後爲了方便你們學習,總結了學習過程當中遇到的幾個關鍵詞:重入鎖、自旋鎖、有序節點、阻塞、非阻塞、監聽,但願對你們有所幫助。

本文做者:小柒2012

閱讀原文

本文爲雲棲社區原創內容,未經容許不得轉載。

相關文章
相關標籤/搜索