如下圖所示 ,當nignx 併發量到達10w ,tomcat1,tomcat2,tomcat3 都是訂單服務,在如此高的併發量下面, 如果不做分布式鎖,那麼後台生成的訂單編號必定重複。如果不是分布式的話,那麼只要加鎖就行, 可是分布式的話,不是同乙個jvm那麼 加sync 鎖也是不行的.
那麼我們如何去解決呢?看下圖
當這三個tomcat 去建立訂單的時候先去zookeeper 的某個資料夾下加把鎖(建立個檔案),當某個tomcat 申請鎖成功後(建立某個檔案成功) ,另外兩個tomcat 就等待(同乙個目錄下不能建立同樣名字的檔案)。
我用個模擬的方法說一遍。 比如這三個tomcat 生成訂單號的時候, 都要去/lock目錄下生成createorderid 這個名字的資料夾,當tomcat2 建立資料夾成功了,tomcat1,和tomcat2 就不能建立createorderid這個名字的資料夾了,因為相同目錄下資料夾的名字不能重複。這樣建立不了資料夾的就當做沒有獲取到鎖。當建立成功資料夾的時候。我們通過get 檔名的命令可以回去到很多資訊有乙個就是sessionid ,根據session 可以判斷是和建立檔案的客戶端斷開連線了,如果斷開則銷毀臨時檔案(下圖中ephemeralowner 即臨時檔案所有者就是sessionid)。這樣我們可以通過關閉客戶端來釋放鎖。
lock()是獲取鎖的方法,先是試著獲取鎖trylock()如果成功列印資訊,否則等待著釋放鎖再去獲取鎖
@override
public void lock() else
}protected abstract boolean trylock();
protected abstract void waitforlock();
/**釋放鎖
*/@override
public void unlock()
client.createephemeral(path);就是去建立臨時節點成功就返回true,否者獲取鎖失敗waitforlock()就是監聽需要建立的資料夾,
向client 註冊監聽事件.如果當前路勁是存在的,則阻塞在這邊。當檔案狀態是刪除的,觸發監聽事件,所有的countdownlauch全部放行。並且這時候取消監聽事件 waitforlock()的方法全部走完,再走上圖**段中的else 裡面的lock()方法繼續去競爭鎖
public class zklockimpl extends zkabstractlock catch (zkexception e)
}/**
* waitforlock要監控前面的那個執行緒的/lock節點
* 要知道/lock節點有沒有刪除
*/@override
protected void waitforlock()
@override
public void handledatadeleted(string datapath) throws exception }};
//這裡註冊path的事件
client.subscribedatachanges(path, izkdatalistener);
if (client.exists(path)) catch (interruptedexception e)
}client.unsubscribedatachanges(path, izkdatalistener);}}
下面是 運用發射槍(countdownlauch)模擬101 個併發
public class orderservice implements runnable catch (interruptedexception e)
createordernum();
}public void createordernum()
public static void main(string args) }}
private string currentpath;
private string beforepath;
private countdownlatch cdl;
public zkimprovelockimpl()
}
當trylock 的時候看看此類的當前路徑(currentpath)存在不存在。 如果不存在,就在這個永久節點下建立乙個臨時順序節點,若存在,再去判斷這個永久節點下第乙個順序節點是不是自己,如果是則獲取鎖,執行業務,最終關掉客戶端 當客戶端關閉,臨時檔案也會消失。
如果不是則獲取當前檔案(currentpath)的前面乙個檔案, 並且去監聽這個檔案,當他被刪除的時候,解開countdownlatch 再去獲取鎖 執行業務,關閉連線,取消監聽。
@override
protected boolean trylock()
listchildrens = this.client.getchildren(path);
collections.sort(childrens);
//這個就是判斷當前使用者建立的臨時節點的名稱是否跟孩子裡面最新的那個相等,如果相等就代表可以獲得鎖
if(currentpath.equals(path + "/" + childrens.get(0))) else
return false;
}@override
protected void waitforlock()
@override
public void handledatadeleted(string datapath) throws exception }};
client.subscribedatachanges(beforepath,izkdatalistener);
if(client.exists(beforepath)) catch (interruptedexception e)
}client.unsubscribedatachanges(beforepath,izkdatalistener);
}
當然apache裡面有netflix 貢獻出來的curator專案將這些複雜的部分封裝起來了,但是原理我們還是要好好看看的。 zookeeper分布式鎖
方案1 演算法思路 利用名稱唯一性,加鎖操作時,只需要所有客戶端一起建立 test lock節點,只有乙個建立成功,成功者獲得鎖。解鎖時,只需刪除 test lock節點,其餘客戶端再次進入競爭建立節點,直到所有客戶端都獲得鎖。特點 這種方案的正確性和可靠性是zookeeper機制保證的,實現簡單。...
zookeeper分布式鎖
zookeeper節點有4個型別 1.持久型 2.瞬時型 3.持久自動排序型 4.瞬時自動排序型 分布式鎖利用的就是zookeeper中瞬時自動排序型節點特性。一 瞬時自動排序節點 瞬時特點為,當客戶端斷開連線的時候,該節點自動消除。自動排序則為,如果節點名字重複,則自動在該節點名字後新增數字,該數...
zookeeper 分布式鎖
分布式鎖肯定是用在分布式環境下。在分布式環境下,使用分布式鎖的目的也是保證同一時刻只有乙個執行緒來修改共享變數,修改共享快取 前景 jdk提供的鎖只能保證執行緒間的安全性,但分布式環境下,各節點之間的執行緒同步執行卻得不到保障,分布式鎖由此誕生。實現方式有以下幾種 基於資料庫實現分布式鎖 基於快取 ...