天天看點

zookeeper使用(四)--應用場景

一、前言

  在上一篇部落格已經介紹了Zookeeper開源用戶端的簡單實用,本篇講解Zookeeper的應用場景。

二、典型應用場景

  Zookeeper是一個高可用的分布式資料管理和協調架構,并且能夠很好的保證分布式環境中資料的一緻性。在越來越多的分布式系統(Hadoop、HBase、Kafka)中,Zookeeper都作為核心元件使用。

  2.1 資料釋出/訂閱

  資料釋出/訂閱系統,即配置中心。需要釋出者将資料釋出到Zookeeper的節點上,供訂閱者進行資料訂閱,進而達到動态擷取資料的目的,實作配置資訊的集中式管理和資料的動态更新。釋出/訂閱一般有兩種設計模式:推模式和拉模式,服務端主動将資料更新發送給所有訂閱的用戶端稱為推模式;用戶端主動請求擷取最新資料稱為拉模式,Zookeeper采用了推拉相結合的模式,用戶端向服務端注冊自己需要關注的節點,一旦該節點資料發生變更,那麼服務端就會向相應的用戶端推送Watcher事件通知,用戶端接收到此通知後,主動到服務端擷取最新的資料。

  若将配置資訊存放到Zookeeper上進行集中管理,在通常情況下,應用在啟動時會主動到Zookeeper服務端上進行一次配置資訊的擷取,同時,在指定節點上注冊一個Watcher監聽,這樣在配置資訊發生變更,服務端都會實時通知所有訂閱的用戶端,進而達到實時擷取最新配置的目的。

  2.2 負載均衡

  負載均衡是一種相當常見的計算機網絡技術,用來對多個計算機、網絡連接配接、CPU、磁盤驅動或其他資源進行配置設定負載,以達到優化資源使用、最大化吞吐率、最小化響應時間和避免過載的目的。

  使用Zookeeper實作動态DNS服務

  · 域名配置,首先在Zookeeper上建立一個節點來進行域名配置,如DDNS/app1/server.app1.company1.com。

  · 域名解析,應用首先從域名節點中擷取IP位址和端口的配置,進行自行解析。同時,應用程式還會在域名節點上注冊一個資料變更Watcher監聽,以便及時收到域名變更的通知。

  · 域名變更,若發生IP或端口号變更,此時需要進行域名變更操作,此時,隻需要對指定的域名節點進行更新操作,Zookeeper就會向訂閱的用戶端發送這個事件通知,用戶端之後就再次進行域名配置的擷取。

  2.3 命名服務

  命名服務是分步實作系統中較為常見的一類場景,分布式系統中,被命名的實體通常可以是叢集中的機器、提供的服務位址或遠端對象等,通過命名服務,用戶端可以根據指定名字來擷取資源的實體、服務位址和提供者的資訊。Zookeeper也可幫助應用系統通過資源引用的方式來實作對資源的定位和使用,廣義上的命名服務的資源定位都不是真正意義上的實體資源,在分布式環境中,上層應用僅僅需要一個全局唯一的名字。Zookeeper可以實作一套分布式全局唯一ID的配置設定機制。

zookeeper使用(四)--應用場景

  通過調用Zookeeper節點建立的API接口就可以建立一個順序節點,并且在API傳回值中會傳回這個節點的完整名字,利用此特性,可以生成全局ID,其步驟如下

  1. 用戶端根據任務類型,在指定類型的任務下通過調用接口建立一個順序節點,如"job-"。

  2. 建立完成後,會傳回一個完整的節點名,如"job-00000001"。

  3. 用戶端拼接type類型和傳回值後,就可以作為全局唯一ID了,如"type2-job-00000001"。

  2.4 分布式協調/通知

  Zookeeper中特有的Watcher注冊于異步通知機制,能夠很好地實作分布式環境下不同機器,甚至不同系統之間的協調與通知,進而實作對資料變更的實時處理。通常的做法是不同的用戶端都對Zookeeper上的同一個資料節點進行Watcher注冊,監聽資料節點的變化(包括節點本身和子節點),若資料節點發生變化,那麼所有訂閱的用戶端都能夠接收到相應的Watcher通知,并作出相應處理。

  MySQL資料複制總線是一個實時的資料複制架構,用于在不同的MySQL資料庫執行個體之間進行異步資料複制和資料變化通知,整個系統由MySQL資料庫叢集、消息隊列系統、任務管理監控平台、Zookeeper叢集等元件共同構成的一個包含生産者、複制管道、資料消費等部分的資料總線系統。

zookeeper使用(四)--應用場景

  Zookeeper主要負責進行分布式協調工作,在具體的實作上,根據功能将資料複制元件劃分為三個子產品:Core(實作資料複制核心邏輯,将資料複制封裝成管道,并抽象出生産者和消費者概念)、Server(啟動和停止複制任務)、Monitor(監控任務的運作狀态,若資料複制期間發生異常或出現故障則進行告警)

zookeeper使用(四)--應用場景

  每個子產品作為獨立的程序運作在服務端,運作時的資料和配置資訊均儲存在Zookeeper上。

zookeeper使用(四)--應用場景

  ① 任務建立,Core程序啟動時,首先向/mysql_replicator/tasks節點注冊任務,如建立一個子節點/mysql_replicator/tasks/copy_hot/item,若注冊過程中發現該子節點已經存在,說明已經有其他Task機器注冊了該任務,是以其自身不需要再建立該節點。

  ② 任務熱備份,為了應對任務故障或者複制任務所在主機故障,複制元件采用"熱備份"的容災方式,即将同一個複制任務部署在不同的主機上,主備任務機通過Zookeeper互相檢測運作監控狀況。無論在第一步是否建立了任務節點,每台機器都需要在/mysql_replicator/tasks/copy_hot_item/instrances節點上将自己的主機名注冊上去,節點類型為臨時順序節點,在完成子節點建立後,每天任務機器都可以擷取到自己建立的節點名及所有子節點清單,然後通過對比判斷自己是否是所有子節點中序号最小的,若是,則将自己運作狀态設定為RUNNING,其他機器設定為STANDBY,這種政策稱為小序号優先政策。

  ③ 熱備切換,完成運作狀态的标示後,其中标記為RUNNING的用戶端機器進行正常的資料複制,而标記為STANDBY的機器則進入待命狀态,一旦RUNNING機器出現故障,那麼所有标記為STANDBY的機器再次按照小序号優先政策來選出RUNNIG機器運作(STANDY機器需要在/mysql_replicator/tasks/copy_hot_item/instances節點上注冊一個子節點清單變更監聽,RUNNING機器當機與Zookeeper斷開連接配接後,對應的節點也會消失,于是所有用戶端收到通知,進行新一輪選舉)。

  ④ 記錄執行狀态,RUNNING機器需要将運作時的上下文狀态保留給STANDBY機器。

  ⑤ 控制台協調,Server的主要工作就是進行任務控制,通過Zookeeper來對不同任務進行控制和協調,Server會将每個複制任務對應生産者的中繼資料及消費者的相關資訊以配置的形式寫入任務節點/mysql_replicator/tasks/copy_hot_item中去,以便該任務的所有任務機器都能夠共享複制任務的配置。

  在上述熱備份方案中,針對一個任務,都會至少配置設定兩台任務機器來進行熱備份(RUNNING和STANDBY、即主備機器),若需要MySQL執行個體需要進行資料複制,那麼需要消耗太多機器。此時,需要使用冷備份方案,其對所有任務進行分組。

zookeeper使用(四)--應用場景

  Core程序被配置了所屬組(Group),即若一個Core程序被标記了group1,那麼在Core程序啟動後,會到對應的Zookeeper group1節點下面擷取所有的Task清單,假如找到任務"copy_hot_item"之後,就會周遊這個Task清單的instances節點,但凡還沒有子節點,則建立一個臨時的順序節點如/mysql_replicator/task-groups/group1/copy_hot_item/instances/[Hostname]-1,當然,在這個過程中,其他Core程序也會在這個instances節點下建立類似的子節點,按照"小序号優先"政策确定RUNNING,不同的是,其他Core程序會自動删除自己建立的子節點,然後周遊下一個Task節點,這樣的過程稱為冷備份掃描,這樣,所有的Core程序在掃描周期内不斷地對相應的Group下來的Task進行冷備份。

  在絕大多數分布式系統中,系統機器間的通信無外乎心跳檢測、工作進度彙報和系統排程。

  ① 心跳檢測,不同機器間需要檢測到彼此是否在正常運作,可以使用Zookeeper實作機器間的心跳檢測,基于其臨時節點特性(臨時節點的生存周期是用戶端會話,用戶端若當即後,其臨時節點自然不再存在),可以讓不同機器都在Zookeeper的一個指定節點下建立臨時子節點,不同的機器之間可以根據這個臨時子節點來判斷對應的用戶端機器是否存活。通過Zookeeper可以大大減少系統耦合。

  ② 工作進度彙報,通常任務被分發到不同機器後,需要實時地将自己的任務執行進度彙報給分發系統,可以在Zookeeper上選擇一個節點,每個任務用戶端都在這個節點下面建立臨時子節點,這樣不僅可以判斷機器是否存活,同時各個機器可以将自己的任務執行進度寫到該臨時節點中去,以便中心系統能夠實時擷取任務的執行進度。

  ③ 系統排程,Zookeeper能夠實作如下系統排程模式:分布式系統由控制台和一些用戶端系統兩部分構成,控制台的職責就是需要将一些指令資訊發送給所有的用戶端,以控制他們進行相應的業務邏輯,背景管理人員在控制台上做一些操作,實際上就是修改Zookeeper上某些節點的資料,Zookeeper可以把資料變更以時間通知的形式發送給訂閱用戶端。

  2.5 叢集管理

  Zookeeper的兩大特性:

  · 用戶端如果對Zookeeper的資料節點注冊Watcher監聽,那麼當該資料及诶單内容或是其子節點清單發生變更時,Zookeeper伺服器就會向訂閱的用戶端發送變更通知。

  · 對在Zookeeper上建立的臨時節點,一旦用戶端與伺服器之間的會話失效,那麼臨時節點也會被自動删除。

  利用其兩大特性,可以實作叢集機器存活監控系統,若監控系統在/clusterServers節點上注冊一個Watcher監聽,那麼但凡進行動态添加機器的操作,就會在/clusterServers節點下建立一個臨時節點:/clusterServers/[Hostname],這樣,監控系統就能夠實時監測機器的變動情況。下面通過分布式日志收集系統的典型應用來學習Zookeeper如何實作叢集管理。

  分布式日志收集系統的核心工作就是收集分布在不同機器上的系統日志,在典型的日志系統架構設計中,整個日志系統會把所有需要收集的日志機器分為多個組别,每個組别對應一個收集器,這個收集器其實就是一個背景機器,用于收集日志,對于大規模的分布式日志收集系統場景,通常需要解決兩個問題:

  · 變化的日志源機器

  · 變化的收集器機器

  無論是日志源機器還是收集器機器的變更,最終都可以歸結為如何快速、合理、動态地為每個收集器配置設定對應的日志源機器。使用Zookeeper的場景步驟如下

  ① 注冊收集器機器,在Zookeeper上建立一個節點作為收集器的根節點,例如/logs/collector的收集器節點,每個收集器機器啟動時都會在收集器節點下建立自己的節點,如/logs/collector/[Hostname]

zookeeper使用(四)--應用場景

  ② 任務分發,所有收集器機器都建立完對應節點後,系統根據收集器節點下子節點的個數,将所有日志源機器分成對應的若幹組,然後将分組後的機器清單分别寫到這些收集器機器建立的子節點,如/logs/collector/host1上去。這樣,收集器機器就能夠根據自己對應的收集器節點上擷取日志源機器清單,進而開始進行日志收集工作。

  ③ 狀态彙報,完成任務分發後,機器随時會當機,是以需要有一個收集器的狀态彙報機制,每個收集器機器上建立完節點後,還需要再對應子節點上建立一個狀态子節點,如/logs/collector/host/status,每個收集器機器都需要定期向該結點寫入自己的狀态資訊,這可看做是心跳檢測機制,通常收集器機器都會寫入日志收集狀态資訊,日志系統通過判斷狀态子節點最後的更新時間來确定收集器機器是否存活。

  ④ 動态配置設定,若收集器機器當機,則需要動态進行收集任務的配置設定,收集系統運作過程中關注/logs/collector節點下所有子節點的變更,一旦有機器停止彙報或有新機器加入,就開始進行任務的重新配置設定,此時通常由兩種做法:

  · 全局動态配置設定,當收集器機器當機或有新的機器加入,系統根據新的收集器機器清單,立即對所有的日志源機器重新進行一次分組,然後将其配置設定給剩下的收集器機器。

  · 局部動态配置設定,每個收集器機器在彙報自己日志收集狀态的同時,也會把自己的負載彙報上去,如果一個機器當機了,那麼日志系統就會把之前配置設定給這個機器的任務重新配置設定到那些負載較低的機器,同樣,如果有新機器加入,會從那些負載高的機器上轉移一部分任務給新機器。

  上述步驟已經完整的說明了整個日志收集系統的工作流程,其中有兩點注意事項。

  ①節點類型,在/logs/collector節點下建立臨時節點可以很好的判斷機器是否存活,但是,若機器挂了,其節點會被删除,記錄在節點上的日志源機器清單也被清除,是以需要選擇持久節點來辨別每一台機器,同時在節點下分别建立/logs/collector/[Hostname]/status節點來表征每一個收集器機器的狀态,這樣,既能實作對所有機器的監控,同時機器挂掉後,依然能夠将配置設定任務還原。

  ② 日志系統節點監聽,若采用Watcher機制,那麼通知的消息量的網絡開銷非常大,需要采用日志系統主動輪詢收集器節點的政策,這樣可以節省網絡流量,但是存在一定的延時。

  2.6 Master選舉

  在分布式系統中,Master往往用來協調叢集中其他系統單元,具有對分布式系統狀态變更的決定權,如在讀寫分離的應用場景中,用戶端的寫請求往往是由Master來處理,或者其常常處理一些複雜的邏輯并将處理結果同步給其他系統單元。利用Zookeeper的強一緻性,能夠很好地保證在分布式高并發情況下節點的建立一定能夠保證全局唯一性,即Zookeeper将會保證用戶端無法重複建立一個已經存在的資料節點。

  首先建立/master_election/2016-11-12節點,用戶端叢集每天會定時往該節點下建立臨時節點,如/master_election/2016-11-12/binding,這個過程中,隻有一個用戶端能夠成功建立,此時其變成master,其他節點都會在節點/master_election/2016-11-12上注冊一個子節點變更的Watcher,用于監控目前的Master機器是否存活,一旦發現目前Master挂了,其餘用戶端将會重新進行Master選舉。

zookeeper使用(四)--應用場景

  2.7 分布式鎖

  分布式鎖用于控制分布式系統之間同步通路共享資源的一種方式,可以保證不同系統通路一個或一組資源時的一緻性,主要分為排它鎖和共享鎖。

  排它鎖又稱為寫鎖或獨占鎖,若事務T1對資料對象O1加上了排它鎖,那麼在整個加鎖期間,隻允許事務T1對O1進行讀取和更新操作,其他任何事務都不能再對這個資料對象進行任何類型的操作,直到T1釋放了排它鎖。

zookeeper使用(四)--應用場景

  ① 擷取鎖,在需要擷取排它鎖時,所有用戶端通過調用接口,在/exclusive_lock節點下建立臨時子節點/exclusive_lock/lock。Zookeeper可以保證隻有一個用戶端能夠建立成功,沒有成功的用戶端需要注冊/exclusive_lock節點監聽。

  ② 釋放鎖,當擷取鎖的用戶端當機或者正常完成業務邏輯都會導緻臨時節點的删除,此時,所有在/exclusive_lock節點上注冊監聽的用戶端都會收到通知,可以重新發起分布式鎖擷取。

  共享鎖又稱為讀鎖,若事務T1對資料對象O1加上共享鎖,那麼目前事務隻能對O1進行讀取操作,其他事務也隻能對這個資料對象加共享鎖,直到該資料對象上的所有共享鎖都被釋放。

zookeeper使用(四)--應用場景

  ① 擷取鎖,在需要擷取共享鎖時,所有用戶端都會到/shared_lock下面建立一個臨時順序節點,如果是讀請求,那麼就建立例如/shared_lock/host1-R-00000001的節點,如果是寫請求,那麼就建立例如/shared_lock/host2-W-00000002的節點。

  ② 判斷讀寫順序,不同僚務可以同時對一個資料對象進行讀寫操作,而更新操作必須在目前沒有任何事務進行讀寫情況下進行,通過Zookeeper來确定分布式讀寫順序,大緻分為四步。

    1. 建立完節點後,擷取/shared_lock節點下所有子節點,并對該節點變更注冊監聽。

    2. 确定自己的節點序号在所有子節點中的順序。

    3. 對于讀請求:若沒有比自己序号小的子節點或所有比自己序号小的子節點都是讀請求,那麼表明自己已經成功擷取到共享鎖,同時開始執行讀取邏輯,若有寫請求,則需要等待。對于寫請求:若自己不是序号最小的子節點,那麼需要等待。

    4. 接收到Watcher通知後,重複步驟1。

  ③ 釋放鎖,其釋放鎖的流程與獨占鎖一緻。

  上述共享鎖的實作方案,可以滿足一般分布式叢集競争鎖的需求,但是如果機器規模擴大會出現一些問題,下面着重分析判斷讀寫順序的步驟3。

zookeeper使用(四)--應用場景

  針對如上圖所示的情況進行分析

  1. host1首先進行讀操作,完成後将節點/shared_lock/host1-R-00000001删除。

  2. 餘下4台機器均收到這個節點移除的通知,然後重新從/shared_lock節點上擷取一份新的子節點清單。

  3. 每台機器判斷自己的讀寫順序,其中host2檢測到自己序号最小,于是進行寫操作,餘下的機器則繼續等待。

  4. 繼續...

  可以看到,host1用戶端在移除自己的共享鎖後,Zookeeper發送了子節點更變Watcher通知給所有機器,然而除了給host2産生影響外,對其他機器沒有任何作用。大量的Watcher通知和子節點清單擷取兩個操作會重複運作,這樣會造成系能鞥影響和網絡開銷,更為嚴重的是,如果同一時間有多個節點對應的用戶端完成事務或事務中斷引起節點小時,Zookeeper伺服器就會在短時間内向其他所有用戶端發送大量的事件通知,這就是所謂的羊群效應。

  可以有如下改動來避免羊群效應。

  1. 用戶端調用create接口常見類似于/shared_lock/[Hostname]-請求類型-序号的臨時順序節點。

  2. 用戶端調用getChildren接口擷取所有已經建立的子節點清單(不注冊任何Watcher)。

  3. 如果無法擷取共享鎖,就調用exist接口來對比自己小的節點注冊Watcher。對于讀請求:向比自己序号小的最後一個寫請求節點注冊Watcher監聽。對于寫請求:向比自己序号小的最後一個節點注冊Watcher監聽。

  4. 等待Watcher通知,繼續進入步驟2。

  此方案改動主要在于:每個鎖競争者,隻需要關注/shared_lock節點下序号比自己小的那個節點是否存在即可。

  2.8 分布式隊列

  分布式隊列可以簡單分為先入先出隊列模型和等待隊列元素聚集後統一安排處理執行的Barrier模型。

  ① FIFO先入先出,先進入隊列的請求操作先完成後,才會開始處理後面的請求。FIFO隊列就類似于全寫的共享模型,所有用戶端都會到/queue_fifo這個節點下建立一個臨時節點,如/queue_fifo/host1-00000001。

zookeeper使用(四)--應用場景

  建立完節點後,按照如下步驟執行。

  1. 通過調用getChildren接口來擷取/queue_fifo節點的所有子節點,即擷取隊列中所有的元素。

  2. 确定自己的節點序号在所有子節點中的順序。

  3. 如果自己的序号不是最小,那麼需要等待,同時向比自己序号小的最後一個節點注冊Watcher監聽。

  4. 接收到Watcher通知後,重複步驟1。

  ② Barrier分布式屏障,最終的合并計算需要基于很多并行計算的子結果來進行,開始時,/queue_barrier節點已經預設存在,并且将結點資料内容指派為數字n來代表Barrier值,之後,所有用戶端都會到/queue_barrier節點下建立一個臨時節點,例如/queue_barrier/host1。

zookeeper使用(四)--應用場景

  建立完節點後,按照如下步驟執行。

  1. 通過調用getData接口擷取/queue_barrier節點的資料内容,如10。

  2. 通過調用getChildren接口擷取/queue_barrier節點下的所有子節點,同時注冊對子節點變更的Watcher監聽。

  3. 統計子節點的個數。

  4. 如果子節點個數還不足10個,那麼需要等待。

  5. 接受到Wacher通知後,重複步驟3。

三、總結

  本篇部落格講解了如何利用Zookeeper的特性來完成典型應用,展示了Zookeeper在解決分布式問題上的強大作用,基于Zookeeper對分布式資料一緻性的保證及其特性,開發人員能夠建構出自己的分布式系統。也謝謝各位園友的觀看~

出處:http://www.cnblogs.com/leesf456/ 

繼續閱讀