一、執行緒鎖、行程鎖
在介紹分布式鎖之前,我們先來簡單介紹下執行緒鎖、行程鎖,
執行緒鎖
執行緒鎖,主要用來解決的問題是:保護臨界區域,
使用方式:lock(mutex)、unlock(mutex),
行程鎖
為了控制同一作業系統中多個行程訪問一個共享資源,
nginx中的accept鎖,就是一種行程鎖,它采用的實作方式是:共享記憶體+信號量,
二、分布式鎖
2.1 分布式鎖的實作方案
分布式鎖的常見實作方案有:
1)資料庫 redis,mysql
2)zookeeper
高效性比較:zookeeper > redis > mysql
2.2、分布式鎖有哪些特征
1)互斥性
2)可重入性:一個行程允許遞回獲取鎖(需要遞回釋放)
3)分布式鎖需要解決鎖超時(行程crash掉,需要考慮釋放分布式鎖)
4)高效、高可用(redis、zookeeper),
5)公平鎖(按獲取鎖順序執行)和非公平鎖(隨機執行)
圖1

高可用,指的是資料中心crash掉后 ,行程依然可以獲取到鎖,并能夠正確釋放鎖,
redis主從復制:主redis收到寫操作,通知從redis方式實作資料同步,實作的是最終一致性(可能一秒rdb或者一個操作aof),
zookeeper:使用zab協議,實作強一致性,
分布式中,主要考慮CAP,c一致性,a可用性,p磁區容錯性(三者占二),
2.3、redis實作分布式鎖
1、redis運行原理
redis用作快取資料庫,也是資料結構資料庫,kv資料庫(hash),
圖2

熱點資料(常用)存放在redis中,
操作redis,實際是操作redis中的資料結構,rpc遠程呼叫,
資料請求方式:請求回應+監聽發布,
按請求順序來執行命令,同樣回傳按照執行順序,
比如:
請求:set hello world
回應:+OK
2、redis實作分布式鎖
1)獲取鎖
2)執行邏輯
3)釋放鎖
設定鎖:setnx()只有在key不存在的時候,才能設定成功,成功回傳(+ok),失敗回傳(nil),
釋放鎖:del key
結合 圖1,引出幾個問題,
問題1 行程a、b、c、d同時競爭鎖,若產生了死鎖,如何解決?
給行程的鎖設定超時時間:set(“lock”, 四元組, “NX”, “EX”, 30) ,比如行程A超時了,行程B就可以獲取到鎖,
問題2 來自問題1的設定超時解決方案:行程A超時后,還需要釋放鎖嗎?怎么釋放?
可以對行程A的鎖進行超時疊加:set(“lock”, 四元組, “NX”, “EX”, 30)超時后,可以依次續時間:20s,10s,
問題3 同樣來自問題1的設定超時解決方案:當A設定鎖超時之后,B可以獲取到鎖,如果B還沒執行完邏輯而A執行完后,A釋放了鎖,這時C也可以獲取鎖,
我們可以通過增加是哪個行程標識,表明是哪個進行在使用鎖,這樣A就不能隨意釋放鎖,
問題4 來自問題3的設定超時解決方案:如何對一個行程進行唯一標識?
1)方案1:使用 “PID” 作為行程唯一標識,缺陷:PID是一個遞增ID,最大值有上限,約是32970,當ID值增加到最大值的時候,系統就會重新從1開始分配PID,沒法區分,因此僅使用PID并不合適,
2)方案2:使用 “IP:PORT:PID” 作為行程唯一標識:會產生一種bug–可能通過批處理執行過很多命令,1270pid輪詢重啟后又變成1270,這個時候沒法區分該行程是否有重啟,
3)方案3:使用 “IP:PORT:STARTTIME:PID” 作為行程唯一標識,starttime是以ms單位來存盤,
2.4、zookeeper實作分布式鎖
zookeeper主要處理協調管理功能:統一命名、管理集群、配置中心(配置更新)、分布式鎖,
圖3

集成zookeeper之后,一般都是配置一個Web后臺,可以在Web后臺對zookeeper進行配置更新,Zookeeper就可以呼叫批處理程式,比如重啟等,
zookeeper通過資料模型+監聽機制,來驅動所有的功能,
1、資料模型
類似檔案系統存盤方式
/root
/usr/local
特征:
1)持久的:持久化(寫到硬碟中,重啟后讀到記憶體中)
2)短暫的:與連接相關,連接斷開后,連接創建的節點自動洗掉
3)順序的(如圖4)
圖4

2、監聽機制
可監聽節點的變化(創建,洗掉,值的變化,子節點的變化(創建或洗掉)),
1)獲取鎖:創建同名節點,只有一個能創建成功,
2)釋放鎖:delete節點,斷開連接自動洗掉,鎖超時,
結合 圖3,引出幾個問題,
問題1 如果有多個行程都去創建,只有一個創建成功了,假設a創建成功了,bcd什么時候去創建呢?
可以使用監聽機制,當節點失效的時候,都去競爭鎖,小于10個行程競爭的時候,可以使用這種方式;而如果有大量行程獲取鎖,就會驚群效應,浪費網路資源,
問題2 來自問題1,如何解決驚群問題?
可以采用公平鎖:
1)創建節點,產生短暫順序節點,比如abcd依次創建,得到的短暫順序節點0、1、2、3,
2)每一個行程都有一個序號 , 假設序號為0,就是它獲取鎖;假設序號不為0,只需要監聽比它小一節的節點即可,
比如:b節點監聽a節點,只要a釋放,b就能拿到鎖,以此類推:c監聽b節點,d監聽c節點,
問題3 來自問題2,行程a當前獲取到鎖,如果行程b崩潰,行程c如何能拿到鎖?
改為行程c監聽行程a,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/252657.html
標籤:其他
