學 Zookeeper 就是為了用它歧匈,接下來我就介紹以下常用的使用場景吴叶。
1钩杰、數(shù)據(jù)發(fā)布/訂閱
1.1双泪、介紹
數(shù)據(jù)發(fā)布/訂閱景描,顧名思義就是發(fā)布者將數(shù)據(jù)發(fā)布到 Zookeeper 上挂捅,然后供訂閱者進行數(shù)據(jù)訂閱和監(jiān)控坝撑,進而實現(xiàn)動態(tài)改變和獲取數(shù)據(jù)的目的蜂厅。
1.2愉择、示例
需求:當我們部署集群時劫乱,需要重復修改每個節(jié)點的配置信息,節(jié)點少的時候還好锥涕,如果多了衷戈,并且需要修改頻繁的時候就會很浪費時間。此時以數(shù)據(jù)庫連接信息為例层坠,連接信息包括:IP地址殖妇,端口號,用戶名破花,密碼谦趣,數(shù)據(jù)庫名稱。
解決: 為解決上述需求座每,我們可以引入 Zookeeper 作為配置中心前鹅,將所有的配置信息都發(fā)布到 Zookeeper 上,然后供集群所有節(jié)點進行數(shù)據(jù)訂閱和監(jiān)控峭梳,當需要修改配置時舰绘,只需修改 Zookeeper 上的數(shù)據(jù),就可以觸發(fā)所有節(jié)點進行修改。
設(shè)計思路如下:
- 創(chuàng)建一個永久節(jié)點(mysql)表示為數(shù)據(jù)庫連接信息捂寿。
- 在 mysql 節(jié)點下創(chuàng)建多個子節(jié)點口四,表示IP地址,端口號秦陋,用戶名蔓彩,密碼,數(shù)據(jù)庫名稱驳概。
- 所有的客戶端都獲取 mysql 節(jié)點下的子節(jié)點信息赤嚼,并注冊監(jiān)控事件。
- 當數(shù)據(jù)庫連接信息有變化時抡句,所有客戶端都能被觸發(fā)探膊,重新執(zhí)行步驟3。
2待榔、Master選舉
2.1逞壁、介紹
Master 選舉就是從集群中選出一個所謂的 "老大",這里稱之為 Master锐锣,Master 往往用來協(xié)調(diào)集群中其他系統(tǒng)單元腌闯,具有對分布式系統(tǒng)狀態(tài)變更的決定權(quán)。
2.2雕憔、示例
需求:需要從集群選出一個節(jié)點作為主節(jié)點 (Master)姿骏,來處理工作,其他節(jié)點作為從節(jié)點斤彼,當主節(jié)點掛掉時分瘦,其他節(jié)點接著競選主節(jié)點。
解決: 為解決上述需求琉苇,我們可以引入 Zookeeper 服務(wù)嘲玫,通過所有節(jié)點競爭創(chuàng)建同一個節(jié)點(Master),創(chuàng)建成功的為主節(jié)點并扇,其他節(jié)點只能監(jiān)控 Master 節(jié)點去团,當 Master 節(jié)點被刪除時,接著去競爭創(chuàng)建穷蛹。
設(shè)計思路如下:
- 創(chuàng)建一個永久節(jié)點(App1)表示為App1集群土陪。
- 集群中的所有節(jié)點都競爭創(chuàng)建名為 Master 的臨時節(jié)點(這里設(shè)計為臨時節(jié)點的原因是當主節(jié)點宕機時,臨時節(jié)點也就跟著被刪除了)肴熏。
- 創(chuàng)建成功 Master 節(jié)點的集群節(jié)點就是主節(jié)點鬼雀,處理功能,當然還可以將主節(jié)點的一些本地信息存儲到 Master 節(jié)點中蛙吏,供監(jiān)控系統(tǒng)展示主節(jié)點信息取刃。
- 其他集群節(jié)點就對 Master 節(jié)點注冊監(jiān)控蹋肮。
- 當Master 節(jié)點刪除時出刷,其他節(jié)點都收到通知璧疗,重新執(zhí)行步驟2。
3馁龟、分布式鎖
3.1崩侠、介紹
分布式鎖是控制分布式系統(tǒng)之間同步訪問共享資源的一種方式。比如你的項目為單體應(yīng)用是坷檩,就可以使用Synchronize 或者 Lock 鎖來實現(xiàn)同步訪問共享資源却音。但是如果是分布式應(yīng)用,多個應(yīng)用之間如果想同步訪問共享資源時 Synchronize 和 Lock 就不管用了矢炼,所以就提出了分布式鎖的概念∠灯埃現(xiàn)在實現(xiàn)分布式鎖的方式有很多種,比如:Redis句灌,數(shù)據(jù)庫夷陋,Zookeeper。這里只說 Zookeeper 實現(xiàn)分布式鎖的思路胰锌。
3.2骗绕、示例
需求:當一個分布式系統(tǒng)中,需要同步訪問共享某一個資源時资昧,怎么才能防止并發(fā)問題呢酬土?
解決:如果理解了上面的 Master 選舉的思想,應(yīng)該就明白 Zookeeper 怎么實現(xiàn)分布式鎖了(創(chuàng)建指定節(jié)點格带,創(chuàng)建成功的線程就是獲取到鎖)撤缴。但是如果使用上面的方式實現(xiàn)的話有一個問題,如果現(xiàn)在有成千上百個線程同時獲取分布式鎖時叽唱,就會出現(xiàn)羊群效應(yīng)屈呕。
羊群效應(yīng):當并發(fā)量比較高時,當線程釋放鎖時尔觉,其他所有的線程都需要搶占鎖(即創(chuàng)建鎖節(jié)點)凉袱,就會出現(xiàn)大量的創(chuàng)建請求,所以就出現(xiàn)了羊群效應(yīng)侦铜。如何解決羊群效應(yīng)呢专甩?請看下圖:
設(shè)計思路如下:
- 當線程需要獲取鎖時,就創(chuàng)建一個節(jié)點路徑為 lock 的臨時有序節(jié)點(使用臨時節(jié)點是為了防止死鎖的問題)钉稍。
- 獲取 /MyLock 的子節(jié)點列表涤躲。
- 判斷自己創(chuàng)建的節(jié)點是否為第一個。
- 如果是第一個贡未,說明獲取到了鎖种樱,執(zhí)行業(yè)務(wù)代碼蒙袍。
- 如果不是第一個,就對自己的前一個節(jié)點注冊監(jiān)控嫩挤,當前一個節(jié)點刪除時害幅,就重新執(zhí)行步驟2。
- 當執(zhí)行完業(yè)務(wù)代碼時岂昭,刪除自己創(chuàng)建的節(jié)點以现。
這樣每次釋放鎖,就不會讓其他所有線程都去搶占鎖约啊,只需要讓下一個節(jié)點去搶占鎖就可以了邑遏。避免了羊群效應(yīng)。
注意:上面講述的是排他鎖恰矩,只有一個線程能獲取到鎖记盒。如果想實現(xiàn)讀寫鎖,該怎么進行變形呢外傅?自己可以嘗試思考一下纪吮。
4、分布式唯一性ID
4.1栏豺、介紹
在過去的單庫單表型系統(tǒng)中彬碱,通常可以使用數(shù)據(jù)庫字段自帶的auto_increment屬性來自動為每條記錄生成一個唯一的ID奥洼。但是分庫分表后巷疼,就無法在依靠數(shù)據(jù)庫的auto_increment屬性來唯一標識一條記錄了。此時我們就可以用zookeeper在分布式環(huán)境下生成全局唯一ID灵奖。
4.2嚼沿、示例
設(shè)計思路如下:
- 當需要生成唯一性ID 時,就在 /MyID 節(jié)點下創(chuàng)建一個節(jié)點路徑為 id 的持久有序節(jié)點瓷患。
- 獲取創(chuàng)建后的節(jié)點路徑骡尽。
- 將節(jié)點路徑的前綴 id 截取,留下的就是唯一性 ID擅编。
- 然后刪除比自己小的節(jié)點攀细。
也可以使用 /MyID 中的版本號來實現(xiàn) 唯一性 ID。