zookeeper基本常識 原

一、Zookeeper基礎知識

1 zookeeper是一個類似hdfs的樹形文件結構,zookeeper可以用來保證數據在(zk)集羣之間的數據的事務性一致。
2 zookeeper有watch事件,是一次性觸發的,當watch監視的數據發生變化時,通知設置了該watch的client,即watcher。
3 zookeeper有三個角色:Leader,Follower,Observer。
   Follower 和 Observer 都能提供讀服務,不能提供寫服務。兩者唯一的區別在於,Observer機器不參與 Leader 選舉過程,也不參與寫操作的『過半寫成功』策略,因此 Observer 可以在不影響寫性能的情況下提升集羣的讀性能。
4 zookeeper的結構其實就是一個樹形結構,leader就相當於其中的根結點,其它節點就相當於follow節點,每個節點都保留自己的內容。
   zookeeper的節點分兩類:持久節點和臨時節點
          PERSISTENT                        持久化節點
          PERSISTENT_SEQUENTIAL    順序自動編號持久化節點,這種節點會根據當前已存在的節點數自動加 1
          EPHEMERAL                         臨時節點, 客戶端session超時這類節點就會被自動刪除
          EPHEMERAL_SEQUENTIAL    臨時自動編號節點

5 leader選舉
  (1) 變更狀態。Leader掛後,餘下的非Observer服務器都會講自己的服務器狀態變更爲LOOKING,然後開始進入Leader選舉過程。
  (2) 每個Server會發出一個投票。在運行期間,每個服務器上的ZXID可能不同,此時假定Server1的ZXID爲123,Server3的ZXID爲122;在第一輪投票中,Server1和Server3都會投自己,產生投票(1, 123),(3, 122),然後各自將投票發送給集羣中所有機器。
  (3) 接收來自各個服務器的投票。與啓動時過程相同。
  (4) 處理投票。與啓動時過程相同,此時,Server1將會成爲Leader。
  (5) 統計投票。與啓動時過程相同。
  (6) 改變服務器的狀態。與啓動時過程相同。

6 zookeeper的默認端口
   2181:對client端提供服務
   2888:集羣內機器通訊使用(Leader監聽此端口)
   3888:選舉leader使用

7 zookeeper應用場景:
   統一命名服務(Name Service)
   配置管理(Configuration Management)
   集羣管理(Group Membership)
   共享鎖(Locks)
   隊列管理

二、相關名詞

1.CAP定理
  一個分佈式系統不可能同時滿足一致性、可用性和分區容錯性這三個基本需求,最多隻能滿足其中的兩項。
  三個特性如下:
  一致性(Consistency):指數據在多個副本之間保持一致。一個數據更新後,所有的用戶能看到最新的值。
  可用性(Availability):指系統提供的服務必須一直處於可用的狀態,對用戶的每一個操作請求總是能夠在有限的時間內返回結果。
  分區容錯性(Partition tolerance):在遇到任何網絡分區故障的時候,任然需要能夠對外提供滿足一致性和可用性的服務,除非是整個網絡環境都發生了故障。
  CAP定理應用:放棄A或放棄C或放棄P。
2.BASE理論
  是對CAP中的一致性和可用性的權衡結果。即使無法做到強一致性,也可以採用適當的方法達到最終一致性。
  BASE三要素:
  基本可用:系統在發生不可預知的故障時,允許損失部分的可用性(包括響應時間、功能上的損失)。
  弱狀態:也叫軟狀態,與硬狀態相對。存在中間狀態,允許系統在不同節點的數據副本在進行數據同步的時候存在延時。
  最終一致性:系統的所有數據副本,經過一段時間以後,最終能夠達到一致的狀態,不需要實時保證數據的強一致性。
3.ZAB協議
  爲分佈式協調服務Zookeeper專門設計的一種支持崩潰恢復的原子廣播協議。
  ZAB協議包括兩種基本模式:崩潰恢復和消息廣播。
  在消息廣播中,Leader服務器會爲每一個Follower服務器各自分配一個單獨的隊列,將需要廣播的事務依次放入這些隊列中,並根據FIFO的策略進行消息發送。
  崩潰恢復:當Leader服務器出現崩潰或者由於網絡原因導致Leader服務器失去與過半Follower的聯繫,就進入崩潰恢復模式。
  進程正常工作時,處於UP狀態;進程崩潰時,稱爲處於DOWN狀態。
  ZAB協議是整個Zookeeper框架的核心所在,它規定任何時候都需要保證只有一個主進程負責進行消息廣播,如果主進程崩潰了就要選舉一個新的主進程,選舉機制和消息廣播機制是緊密相關。
  ZAB與Paxos的聯繫與區別:
    聯繫:都存在類似於Leader進程的角色,負責協調多個Follower進程的運行;Leader進程都會等待超過半數的Follower做出正確的反饋後,纔會將一個提案進行提交。
    區別:設計目標不一樣。ZAB用於構建一個高可用的分佈式數據主備系統,Paxos用於構建分佈式一致性狀態機系統。
4.Paxos算法:
  包含的角色有:Proposer(申請者)、Acceptor(接收者)、Learner(領導者);
  執行過程:
  提案的選定:一個Proposer向一個或多個Acceptor發提案,由半數以上Acceptor批准的提案會被選定。
  Proposer生成提案:在確定提案後,Proposer會將該提案再次發送給某個Acceptor集合,並期望獲得它們的批准。
  Acceptor批准提案:Aceeptor接到Proposer的Prepare或Accept請求後,做出相應的響應。
  提案的獲取:Learner獲取提案。
  優點:引入“過半”的概念,即少數服從多數的原則,並且支持節點角色之間的輪換,極大地避免了分佈式的出現,也解決了無限等待和“腦裂”等問題。

三、Zookeeper配置

   1 結構:一共三個節點 (zk服務器集羣規模不小於3個節點),要求服務器之間系統時間保持一致。
   2 上傳zk
     1)進行解壓:tar zookeeper-3.4.5.tar.gz 
     2)重命名:mv zookeeper-3.4.5 zookeeper
     3)修改環境變量:vi /etc/profile
        export ZOOKEEPER_HOME=/usr/local/zookeeper
        export PATH=.:$HADOOP_HOME/bin:$ZOOKEEPER_HOME/bin:$JAVA_HOME/...
        刷新:source /etc/profile
     4)修改conf:
        cd /usr/local/zookeeper/conf
        mv zoo_sample.cfg zoo.cfg
     5)修改vi zoo.cfg  
       dataDir=/usr/local/zookeeper/data			
       在最後面添加 
            server.0=bhz:2888:3888
            server.1=hadoop1:2888:3888
            server.2=hadoop2:2888:3888
     6)服務器標識配置: 
        創建文件夾:mkdir data
        創建文件myid並填寫內容爲0:vi myid (內容爲服務器標識 : 0)
        進行復制zookeeper目錄到hadoop01和hadoop02 還有/etc/profile文件
        把hadoop01、hadoop02中的myid文件裏的值修改爲1和2 路徑(vi /usr/local/zookeeper/data/myid)
     7)啓動zookeeper:
        路徑:/usr/local/zookeeper/bin
        執行:zkServer.sh start
        狀態:zkServer.sh status(在三個節點上檢驗zk的mode,一個leader和倆個follower)
    3 操作zookeeper (shell)
       zkCli.sh 進入zookeeper客戶端
       根據提示命令進行操作: 
       查找:ls /   ls /zookeeper
       創建並賦值:create /bhz hadoop
       獲取:get /bhz 
       設值:set /bhz baihezhuo 
       可以看到zookeeper集羣的數據一致性
       創建節點有倆種類型:短暫(ephemeral) 持久(persistent)

四、zoo.cfg詳解:

      tickTime:	基本事件單元,以毫秒爲單位。這個時間是作爲 Zookeeper 服務器之間或客戶端與服務器之間維持心跳的時間間隔,也就是每隔 tickTime時間就會發送一個心跳。
      dataDir:	存儲內存中數據庫快照的位置,顧名思義就是 Zookeeper 保存數據的目錄,默認情況下,Zookeeper 將寫數據的日誌文件也保存在這個目錄裏。
      clientPort:這個端口就是客戶端連接 Zookeeper 服務器的端口,Zookeeper 會監聽這個端口,接受客戶端的訪問請求。
      initLimit:	這個配置項是用來配置 Zookeeper 接受客戶端初始化連接時最長能忍受多少個心跳時間間隔數,當已經超過 10 個心跳的時間(也就是 tickTime)長度後 Zookeeper 服務器還沒有收到客戶端的返回信息,那麼表明這個客戶端連接失敗。總的時間長度就是 10*2000=20 秒。
      syncLimit:這個配置項標識 Leader 與 Follower 之間發送消息,請求和應答時間長度,最長不能超過多少個 tickTime 的時間長度,總的時間長度就是 5*2000=10 秒
      server.A = B:C:D :
                      A表示這個是第幾號服務器,
                      B 是這個服務器的 ip 地址;
                      C 表示的是這個服務器與集羣中的 Leader 服務器交換信息的端口;
                      D 表示的是萬一集羣中的 Leader 服務器掛了,需要一個端口來重新進行選舉,選出一個新的Leader

五、zookeeper的不足

1.zookeeper不是爲高可用性設計的
  由於要跨機房容災,很多系統實際上是需要跨機房部署的。出於性價比的考慮我們通常會讓多個機房同時工作,而不會搭建N倍的冗餘。也就是說單個機房肯定撐不住全流量(你能設想谷歌在全球只剩下一個機房在幹活嗎)。由於zookeeper集羣只能有一個master,因此一旦機房之間連接出現故障,zookeeper master就只能照顧一個機房,其他機房運行的業務模塊由於沒有master都只能停掉。於是所有流量集中到有master的那個機房,於是系統crash。
  即使是在同一個機房裏面,由於網段的不同,在調整機房交換機的時候偶爾也會發生網段隔離的情況。實際上機房每個月基本上都會發生短暫的網絡隔離之類的子網段調整。在那個時刻zookeeper將處於不可用狀態。如果整個業務系統基於zookeeper(比如要求每個業務請求都先去zookeeper獲取業務系統的master地址),則系統的可用性將非常脆弱。
  由於zookeeper對於網絡隔離的極度敏感,導致zookeeper對於網絡的任何風吹草動都會做出激烈反應。這使得zookeeper的‘不可用’時間比較多,我們不能讓zookeeper的‘不可用’,變成系統的不可用。
2.zookeeper的選舉過程速度很慢
  這是一個很難從理論分析上看到的弱點,但是你一旦遇到就會痛不欲生。
  前面我們已經說過,網絡實際上常常是會出現隔離等不完整狀態的,而zookeeper對那種情況非常敏感。一旦出現網絡隔離,zookeeper就要發起選舉流程。
  zookeeper的選舉流程通常耗時30到120秒,期間zookeeper由於沒有master,都是不可用的。
  對於網絡裏面偶爾出現的,比如半秒一秒的網絡隔離,zookeeper會由於選舉過程,而把不可用時間放大幾十倍。
3.zookeeper的性能是有限的
  典型的zookeeper的tps大概是一萬多,無法覆蓋系統內部每天動輒幾十億次的調用。因此每次請求都去zookeeper獲取業務系統master信息是不可能的。
  因此zookeeper的client必須自己緩存業務系統的master地址。
  因此zookeeper提供的‘強一致性’實際上是不可用的。如果我們需要強一致性,還需要其他機制來進行保障:比如用自動化腳本把業務系統的old master給kill掉,但是那會有很多陷阱(這裏先不展開這個議題,讀者可以自己想想會有哪些陷阱)。
4.zookeeper的權限控制非常薄弱
  在大型的複雜系統裏面,使用zookeeper必須自己再額外的開發一套權限控制系統,通過那套權限控制系統再訪問zookeeper
  額外的權限控制系統不但增加了系統複雜性和維護成本,而且降低了系統的總體性能
5.即使有了zookeeper也很難避免業務系統的數據不一致
  前面已經討論過了,由於zookeeper的性能限制,我們無法讓每次系統內部調用都走zookeeper,因此總有某些時刻,業務系統會存在兩個master(業務系統client那邊緩存的業務系統master信息是定時從zookeeper更新的,因此會有更新不同步的問題)。
  如果要在業務系統client的master信息不一直的情況下,仍要保持系統的數據一致性,唯一的方法是“先kill掉老master,再在zookeeper上更新master信息”。但是在是否要kill current master這個問題上,程序是無法完全自動決定的(因爲網絡隔離的時候zookeeper已經不可用了,自動腳本沒有全局信息,不管怎麼做都可能是錯的,什麼都不做也可能是錯的。當網絡故障的時候,只有運維人員纔有全局信息,程序是無法接電話得知其他機房的情況的)。因此係統無法自動的保障數據一致性,必須要人工介入。而人工介入的典型時間是半個小時以上,我們不能讓系統這麼長時間不可用。因此我們必須在某個方向上進行妥協,最常見的妥協方式是放棄‘強一致性’,而接受‘最終一致性’。
  如果我們需要人工介入才能保證‘可靠的強一致性’,那麼zookeeper的價值就大打折扣。

六、zookeeper應用場景

1.數據發佈與訂閱(配置中心)
  數據發佈與訂閱,即所謂的配置中心,顧名思義就是發佈者將數據發佈到 ZooKeeper 節點上,供訂閱者進行數據訂閱,進而達到動態獲取數據的目的,實現配置信息的集中式管理和動態更新。
  發佈/訂閱系統一般有兩種設計模式,分別是推(Push)和拉(Pull)模式。
      - 推模式
        服務端主動將數據更新發送給所有訂閱的客戶端
      - 拉模式
        客戶端主動發起請求來獲取最新數據,通常客戶端都採用定時輪詢拉取的方式
  ZooKeeper 採用的是推拉相結合的方式:
    客戶端向服務端註冊自己需要關注的節點,一旦該節點的數據發生變更,那麼服務端就會向相應的客戶端發送Watcher事件通知,客戶端接收到這個消息通知後,需要主動到服務端獲取最新的數據

2.命名服務
  命名服務也是分佈式系統中比較常見的一類場景。在分佈式系統中,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源或服務的地址,提供者等信息。被命名的實體通常可以是集羣中的機器,提供的服務,遠程對象等等——這些我們都可以統稱他們爲名字。
  其中較爲常見的就是一些分佈式服務框架(如RPC)中的服務地址列表。通過在ZooKeepr裏創建順序節點,能夠很容易創建一個全局唯一的路徑,這個路徑就可以作爲一個名字。
  ZooKeeper 的命名服務即生成全局唯一的ID。

3.分佈式協調服務/通知
  ZooKeeper 中特有 Watcher 註冊與異步通知機制,能夠很好的實現分佈式環境下不同機器,甚至不同系統之間的通知與協調,從而實現對數據變更的實時處理。使用方法通常是不同的客戶端如果 機器節點 發生了變化,那麼所有訂閱的客戶端都能夠接收到相應的Watcher通知,並做出相應的處理。
ZooKeeper的分佈式協調/通知,是一種通用的分佈式系統機器間的通信方式。

4.Master選舉
  利用 ZooKeepr 的強一致性,能夠很好地保證在分佈式高併發情況下節點的創建一定能夠保證全局唯一性,即 ZooKeeper 將會保證客戶端無法創建一個已經存在的 數據單元節點。
  也就是說,如果同時有多個客戶端請求創建同一個臨時節點,那麼最終一定只有一個客戶端請求能夠創建成功。利用這個特性,就能很容易地在分佈式環境中進行 Master 選舉了。
  成功創建該節點的客戶端所在的機器就成爲了 Master。同時,其他沒有成功創建該節點的客戶端,都會在該節點上註冊一個子節點變更的 Watcher,用於監控當前 Master 機器是否存活,一旦發現當前的Master掛了,那麼其他客戶端將會重新進行 Master 選舉。這樣就實現了 Master 的動態選舉。

5.分佈式鎖
  分佈式鎖是控制分佈式系統之間同步訪問共享資源的一種方式 
  分佈式鎖又分爲排他鎖和共享鎖兩種
  排它鎖 
    定義鎖 
      ZooKeeper 上的一個 機器節點 可以表示一個鎖
    獲得鎖 
      把ZooKeeper上的一個節點看作是一個鎖,獲得鎖就通過創建臨時節點的方式來實現。 
      ZooKeeper 會保證在所有客戶端中,最終只有一個客戶端能夠創建成功,那麼就可以 認爲該客戶端獲得了鎖。同時,所有沒有獲取到鎖的客戶端就需要到/exclusive_lock 節點上註冊一個子節點變更的Watcher監聽,以便實時監聽到lock節點的變更情況。
    釋放鎖 
      因爲鎖是一個臨時節點,釋放鎖有兩種方式
      當前獲得鎖的客戶端機器發生宕機或重啓,那麼該臨時節點就會被刪除,釋放鎖。
      正常執行完業務邏輯後,客戶端就會主動將自己創建的臨時節點刪除,釋放鎖。
      無論在什麼情況下移除了lock節點,ZooKeeper 都會通知所有在 /exclusive_lock 節點上註冊了節點變更 Watcher 監聽的客戶端。這些客戶端在接收到通知後,再次重新發起分佈式鎖獲取,即重複『獲取鎖』過程。

  共享鎖
    共享鎖在同一個進程中很容易實現,但是在跨進程或者在不同 Server 之間就不好實現了。Zookeeper 卻很容易實現這個功能,實現方式也是需要獲得鎖的 Server 創建一個 EPHEMERAL_SEQUENTIAL 目錄節點,然後調用 getChildren方法獲取當前的目錄節點列表中最小的目錄節點是不是就是自己創建的目錄節點,如果正是自己創建的,那麼它就獲得了這個鎖,如果不是那麼它就調用 exists(String path, boolean watch) 方法並監控 Zookeeper 上目錄節點列表的變化,一直到自己創建的節點是列表中最小編號的目錄節點,從而獲得鎖,釋放鎖很簡單,只要刪除前面它自己所創建的目錄節點就行了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章