ZooKeeper:01---ZooKeeper入門概述、分佈式協作的難點

一、簡介

  • 在計算機誕⽣之後很長的⼀段時間⾥,⼀個應⽤服務是在⼀個獨⽴的單處理器計算機上運⾏⼀段程序。時⾄今⽇,應⽤服務已經發⽣了很⼤的變化。在⼤數據和雲計算盛⾏的今天,應⽤服務由很多個獨⽴的程序組成,這些獨⽴的程序則運⾏在形形⾊⾊、千變萬化的⼀組計算機上
  • 相對於開發在⼀臺計算機上運⾏的單個程序,如何讓⼀個應⽤中多個獨⽴的程序協同⼯作是⼀件⾮常困難的事情。開發這樣的應⽤很容易讓很多開發⼈員陷⼊如何使多個程序協同⼯作的邏輯中,最後導致沒有時間更好地思考和實現他們⾃⼰的應⽤程序邏輯;又或者開發⼈員對協同邏輯關注不夠,只是⽤很少的時間開發了⼀個簡單脆弱的主協調器,導致不可靠的單⼀失效點
  • ZooKeeper的設計保證了其健壯性,這就使得應⽤開發⼈員可以更多關注應⽤本身的邏輯,⽽不是協同⼯作上。ZooKeeper從⽂件系統API得到啓 發,提供⼀組簡單的API,使得開發⼈員可以實現通⽤的協作任務,包括選舉主節點、管理組內成員關係、管理元數據等。ZooKeeper包括⼀個應⽤開發庫(主要提供Java和C兩種語⾔的API)和⼀個⽤Java實現的服務組件。ZooKeeper的服務組件運⾏在⼀組專⽤服務器之上,保證了⾼容錯性和 可擴展性。
  • 當你決定使⽤ZooKeeper來設計應⽤時,最好將應⽤數據和協同數據獨⽴開。⽐如,⽹絡郵箱服務的⽤戶對⾃⼰郵箱中的內容感興趣,但是並不 關⼼由哪臺服務器來處理特定郵箱的請求。在這個例⼦中,郵箱內容就是應⽤數據,⽽從郵箱到某⼀臺郵箱服務器之間的映射關係就是協同數據 (或稱元數據)。整個ZooKeeper服務所管理的就是後者

二、ZooKeeper概述

  • ZooKeeper官網:https://zookeeper.apache.org/
  • Apache ZooKeeper致力於開發和運維分佈式協調服務的一個開源服務
  • 關於ZooKeeper這樣的系統功能的討論都圍繞着⼀條主線:它可以在分佈式系統中協作多個任務。⼀個協作任務是指⼀個包含多個進程的任務。 這個任務可以是爲了協作或者是爲了管理競爭。協作意味着多個進程需要 ⼀同處理某些事情,⼀些進程採取某些⾏動使得其他進程可以繼續⼯作。 ⽐如,在典型的主-從(master-worker)⼯作模式中,從節點處於空閒狀態 時會通知主節點可以接受⼯作,於是主節點就會分配任務給從節點。競爭 則不同。它指的是兩個進程不能同時處理⼯作的情況,⼀個進程必須等待 另⼀個進程。同樣在主-從⼯作模式的例⼦中,我們想有⼀個主節點,但是 很多進程也許都想成爲主節點,因此我們需要實現互斥排他鎖(mutual exclusion)。實際上,我們可以認爲獲取主節點⾝份的過程其實就是獲取 鎖的過程,獲得主節點控制權鎖的進程即主節點進程
  • 如果你曾經有過多線程程序開發的經驗,就會發現很多類似的問題。 實際上,在⼀臺計算機上運⾏的多個進程和跨計算機運⾏的多個進程從概念上區別並不⼤。在多線程情況下有⽤的同步原語在分佈式系統中也同樣 有效。⼀個重要的區別在於,在典型的不共享環境下不同的計算機之間不 共享除了⽹絡之外的其他任何信息。雖然許多消息傳遞算法可以實現同步 原語,但是使⽤⼀個提供某種有序共享存儲的組件往往更加簡便,這正是ZooKeeper所採⽤的⽅式
  • 協同並不總是採取像羣⾸選舉或者加鎖等同步原語的形式。配置元數據也是⼀個進程通知其他進程需要做什麼的⼀種常⽤⽅式。⽐如,在⼀個 主-從系統中,從節點需要知道任務已經分配到它們。即使在主節點發⽣崩 潰的情況下,這些信息也需要有效

原語

  • 操作系統或計算機網絡用語範疇。是由若干條指令組成的,用於完成一定功能的一個過程。具有不可分割性·即原語的執行必須 是連續的,在執行過程中不允許被中斷

ZooKeeper的特點

  • ZooKeeper的特點:
    • 順序一致性:從同一客戶端發起的事務請求,最終將會嚴格地按照順序被應用到 ZooKeeper 中去
    • 原子性: 所有事務請求的處理結果在整個集羣中所有機器上的應用情況是一致的,也就是說,要麼整個集羣中所有的機器都成功應用 了某一個事務,要麼都沒有應用
    • 單一系統映像:無論客戶端連到哪一個ZooKeeper服務器上,其看到的服務端數據模型都是一致的
    • 可靠性:一旦一次更改請求被應用,其所有的集羣服務器上都會被應用
  • 利用這些特點,在系統中數據發佈/訂閱、負載均衡、服務發現、分佈式協調/通知、集羣管理、Master 選舉、分佈式鎖和分佈式隊列等功能

ZooKeeper改變了什麼

  • 使⽤ZooKeeper是否意味着需要以全新的⽅式進⾏應⽤程序開發?事實 並⾮如此,ZooKeeper實際上簡化了開發流程,提供了更加敏捷健壯的⽅ 案
  • ZooKeeper之前的其他⼀些系統採⽤分佈式鎖管理器或者分佈式數據庫 來實現協作。實際上,ZooKeeper也從這些系統中借鑑了很多概念。但是, ZooKeeper的設計更專注於任務協作,並不提供任何鎖的接⼜或通⽤存儲數 據接⼜。同時,ZooKeeper沒有給開發⼈員強加任何特殊的同步原語,使⽤ 起來⾮常靈活
  • 雖然我們也可以不使⽤ZooKeeper來構建分佈式系統,但是使⽤ ZooKeeper可以讓開發⼈員更專注於其應⽤本⾝的邏輯⽽不是神祕的分佈式 系統概念。所以不使⽤ZooKeeper開發分佈式系統也並不是不可能,只是難 度會⽐較⼤

關於ZooKeeper名字的來源

  • ZooKeeper由雅虎研究院開發。小組在進⾏ZooKeeper的開發⼀段 時間之後,開始推薦給其他小組,因此需要爲我們的項目起⼀個名字。與此同時,小組也⼀同致⼒於Hadoop項目,參與了很多動物命名的項 目,其中有⼴爲⼈知的Apache Pig項目(http://pig.apache.org/)。在討論各種各樣的名字時,⼀位團隊成員提到不能再使用動物的名字 了,因爲主管覺得這樣下去會覺得我們⽣活在動物園中。⼤家對此產⽣了共鳴,分佈式系統就像⼀個動物園,混亂且難以管理,而ZooKeeper就是將這⼀切變得可控

ZooKeeper不適⽤的場景

  • 整個ZooKeeper的服務器集羣管理着應⽤協作的關鍵數據。ZooKeeper不適合⽤作海量數據存儲。對於需要存儲海量的應⽤數據的情況,有很多備選⽅案,⽐如說數據庫和分佈式⽂件系統等。因爲不同的應⽤有不同的需求,如對⼀致性和持久性的不同需求,所以在設計應⽤時,最佳實踐還是應該將應⽤數據和協同數據獨⽴開
  • ZooKeeper中實現了⼀組核⼼操作,通過這些可以實現很多常見分佈式 應⽤的任務。你知道有多少應⽤服務採⽤主節點⽅式或進程響應跟蹤⽅ 式?雖然ZooKeeper並沒有爲你實現這些任務,也沒有爲應⽤實現主節點選 舉,或者進程存活與否的跟蹤的功能,但是,ZooKeeper提供了實現這些任 務的⼯具,對於實現什麼樣的協同任務,由開發⼈員⾃⼰決定。

關於Apache項⽬

  • ZooKeeper是⼀個託管到Apache軟件基⾦會(Apache Software Foundation)的開源項⽬,Apache的項⽬管理委員會(Project Management Committee,PMC)負責項⽬管理和監督。只有技術專家可以檢查補丁 (patch),但是任何開發⼈員都可以貢獻補丁。開發⼈員爲項⽬做出貢獻 後也可以成爲技術專家。對項⽬的貢獻不僅僅限於貢獻補丁,也可以通過 其他形式參與項⽬,與社區成員們互動。我們在郵件列表中進⾏很多討 論,如新功能特性、⽤戶反饋的新問題等。我們強烈建議開發⼈員積極參 與開發社區,訂閱郵件列表,並參與討論。如果你想通過⼀些項⽬與 ZooKeeper社區保持長期關係,你也許會發現成爲⼀名技術專家很有價值。

三、ZooKeeper的使用實例

  • ZooKeeper 是一個典型的分佈式數據一致性解決方案,分佈式應用程序可以基於ZooKeeper實現諸如數據發佈/訂閱、負載均衡、命名服 務、分佈式協調/通知、集羣管理、Master 選舉、分佈式鎖和分佈式隊列等功能
  • ZooKeeper一個最常用的使用場景就是用於擔任服務生產者和服務消費者的註冊中心。服務生產者將自己提供的服務註冊到ZooKeeper中心,服務的消費者在進行服務調用的時候先到ZooKeeper中查找服務,獲取到服務生產者的詳細信息之後,再去調用服務生產者的內容與數據。如下圖所示,使用ZooKeeper擔任了註冊中心這一角色

Apache HBase

  • HBase是⼀個通常與Hadoop⼀起使⽤的數據存儲倉庫。在HBase中, ZooKeeper⽤於選舉⼀個集羣內的主節點,以便跟蹤可⽤的服務器,並保存集羣的元數據

Apache Kafka

  • Kafka是⼀個基於發佈-訂閱(pub-sub)模型的消息系統。其中 ZooKeeper⽤於檢測崩潰,實現主題(topic)的發現,並保持主題的⽣產和 消費狀態

Apache Solr

  • Solr是⼀個企業級的搜索平臺。Solr的分佈式版本命名爲SolrCloud,它 使⽤ZooKeeper來存儲集羣的元數據,並協作更新這些元數據

Yahoo!Fetching Service

  • Yahoo!Fetching Service是爬⾍實現的⼀部分,通過緩存內容的⽅式⾼ 效地獲取⽹頁信息,同時確保滿⾜⽹頁服務器的管理規則(⽐如robots.txt ⽂件)。該服務採⽤ZooKeeper實現主節點選舉、崩潰檢測和元數據存儲

Facebook Messages

  • Facebook推出的這個應⽤(http://on.fb.me/1a7uViK)集成了email、短 信、Facebook聊天和Facebook收件箱等通信通道。該應⽤將ZooKeeper作爲 控制器,⽤來實現數據分⽚、故障恢復和服務發現等功能
  • 除了以上介紹的這些應⽤外,還有很多使⽤ZooKeeper的例⼦。根據這些代表應⽤,我們可以從更抽象的層次上討論ZooKeeper。當開發⼈員使⽤ZooKeeper進⾏開發時,開發⼈員設計的那些應⽤往往可以看成⼀組連接到 ZooKeeper服務器端的客戶端,它們通過ZooKeeper的客戶端API連接到 ZooKeeper服務器端進⾏相應的操作。Zookeep的客戶端API功能強⼤,其中包括:
    • 保障強⼀致性、有序性和持久性
    • 實現通用的同步原語的能⼒
    • 在實際分佈式系統中,併發往往導致不正確的⾏爲。ZooKeeper提供 了⼀種簡單的併發處理機制
  • 當然,ZooKeeper也並不是萬能的,我們還不能讓它解決所有問題。對 我們來說,更重要的是要了解ZooKeeper爲我們提供了什麼,並知道如何處理其中的⼀些棘⼿問題。這本書的⽬標之⼀就是討論如何處理這些問題。 我們將介紹ZooKeeper爲開發⼈員提供的各種功能,也會討論我們在開發 ZooKeeper應⽤中遇到的⼀些問題,帶你⾛⼊ZooKeeper的世界。

四、通過ZooKeeper構建分佈式系統

  • ZooKeeper可以單點部署,也可以集羣部署,集羣部署後有多個對外服務提供創建、更新和刪除節點的服務

  • 對分佈式系統的定義有很多,此處我們對分佈式系統的定義爲:分佈式系統是同時跨越多個物理主機,獨⽴運⾏的多個軟件組件所組成的系統。我們採⽤分佈式去設計系統有很多原因,分佈式系統能 夠利⽤多處理器的運算能⼒來運⾏組件,⽐如並⾏複製任務。⼀個系統也 許由於戰略原因,需要分佈在不同地點,⽐如⼀個應⽤由多個不同地點的 服務器提供服務
  • 使⽤⼀個獨⽴的協調組件有⼏個重要的好處:⾸先,我們可以獨⽴地設計和實現該組件,這樣獨⽴的組件可以跨多個應⽤共享。其次,系統架 構師可以簡化協作⽅⾯的⼯作,這些並不是瑣碎的⼩事。最後,系統可以獨⽴地運⾏和協作這些組件,獨⽴這樣的組件,也 簡化了⽣產環境中解決實際問題的任務。
  • 軟件組件以操作系統的進程⽅式運⾏,很多時候還涉及多線程的執⾏。因此ZooKeeper的服務端和客戶端也是以進程的⽅式運⾏,⼀個單獨的 物理主機(⽆論是⼀個獨⽴主機還是⼀個虛擬環境中的操作系統)上運⾏ ⼀個單獨的應⽤進程,儘管進程可能採⽤多線程運⾏的⽅式,以便利⽤現 代處理器的多核(multicore)處理能⼒
  • 分佈式系統中的進程通信有兩種選擇:直接通過⽹絡進⾏信息交換, 或讀寫某些共享存儲。ZooKeeper使⽤共享存儲模型來實現應⽤間的協作和 同步原語。對於共享存儲本⾝,又需要在進程和存儲間進⾏⽹絡通信。我 們強調⽹絡通信的重要性,因爲它是分佈式系統中併發設計的基礎。

真實系統中要注意的問題

  • 消息延遲:消息傳輸可能會發⽣任意延遲,⽐如,因爲⽹絡擁堵。這種任意延遲 可能會導致不可預期的後果。⽐如,根據基準時鐘,進程P先發送了⼀個 消息,之後另⼀個進程Q發送了消息,但是進程Q的消息也許會先完成傳 送
  • 處理器性能:操作系統的調度和超載也可能導致消息處理的任意延遲。當⼀個進程 向另⼀個進程發送消息時,整個消息的延時時間約等於發送端消耗的時 間、傳輸時間、接收端的處理時間的總和。如果發送或接收過程需要調度 時間進⾏處理,消息延時會更⾼。
  • 時鐘偏移:使⽤時間概念的系統並不少見,⽐如,確定某⼀時間系統中發⽣了哪 些事件。處理器時鐘並不可靠,它們之間也會發⽣任意的偏移。因此,依 賴處理器時鐘也許會導致錯誤的決策。
  • 關於這些問題的⼀個重要結果是,在實際情況中,我們很難判斷⼀個 進程是崩潰了還是某些因素導致了延時。沒有收到⼀個進程發送的消息, 可能是該進程已經崩潰,或是最新消息發⽣了⽹絡延遲,或是其他情況導 致進程延遲,或者是進程時鐘發⽣了偏移。我們⽆法確定⼀個被稱爲異步(asynchronous)的系統中的這些區別。
  • 數據中⼼通常使⽤⼤量統⼀的硬件。但即使在數據中⼼,我們需要發 現這些問題對應⽤服務帶來的影響,因爲⼀個應⽤服務使⽤了多代的硬 件,甚⾄對於同⼀批次的硬件也存在微⼩但顯著的性能差異。所有這些事 情使分佈式系統設計師的⽣活越來越複雜
  • ZooKeeper的精確設計簡化了這些問題的處理,ZooKeeper並不是完全 消除這些問題,⽽是將這些問題在應⽤服務層⾯上完全透明化,使得這些 問題更容易處理。ZooKeeper實現了重要的分佈式計算問題的解決⽅案,直 觀爲開發⼈員提供某種程度上實現的封裝,⾄少這是我們⼀直希望的

五、演示案例:主-從應用(以Nginx爲例)

  • 現在很多服務器需要7*24小時工作,加入一臺機器掛了,我們希望能有其他機器頂替他繼續工作。此類問題現在多采用master-slave模式,也就是常說的主-從模式,正常情況下主機提供服務器,備機負責監聽主機狀態,當主機異常時,可以自動切換到備機繼續提供服務(有點類似於數據庫跟備份,備機正常情況下只監聽,不工作),這個切換過程選出下一個主機的過程就是master選舉

  • 舉個例子:比如我們利用nginx作爲代理服務器,把用戶的訪問代理到Web服務器上,如下圖:

  • Master-Slave機制:
    • nginx綁定了一個VIP(虛擬IP地址),然後把用戶請求代理到Web服務器上,那麼如果Nginx出現了故障,不能轉發客戶請求到Web服務器上,於是整個系統就無法對外提供客戶的請求了,系統處於一種不可用的狀態,這就是稱之爲單點故障
    • 面臨這種單點故障,我們應該怎麼理解呢?也就是我們必須對外提供高可用的服務。一種解決辦法是nginx部署多臺(例如2臺)服務器,當一套故障後另一臺對外提供服務,這就是經典的Master-Slave的機制
    • 如下圖,它們之間使用一個PING/PONG機制,去探測對方是否存在,如果收不到對方的PING或者PONG消息,就認爲對端掛掉了
    • 具體的細節看下面的介紹

主節點失效

  • 場景①(狀態恢復):主節點失效時,從節點接管主節點的角色,進行故障轉移,然而,這並不是簡單開始處理進入主節點的請求。從節點需要能夠恢復到舊的主節點崩潰時的狀態。對於主節點狀態的可恢復性,我們不能簡單地從已經崩潰的舊主節點來獲取這些信息,而需要從其他地方獲取,比較好的方法就是從ZooKeeper來獲取
  • 場景②(“腦裂”問題):
    • 狀態恢復並不是唯一的重要問題。假設主節點有效,從節點卻認爲主節點已經崩潰。這種錯誤的假設可能發⽣在以下情況,例如主節點負載很⾼,導致消息任意延遲,導致從節點收不到主節點的PING消息,從節點將認爲主節點已經失效,從會接管成爲主節點⾓⾊,設置VIP,然後對外提供服務。此時系統中出現了兩個主節點
    • 針對這個場景中導致的問題,我們⼀般稱之爲腦裂(splitbrain):系統中兩個或者多個部分開始獨⽴⼯作,導致整體⾏爲不⼀致性
    • 我們需要找出⼀種⽅法來處理主節點失效的情況,關鍵是我們需要避免發⽣腦裂的情況,ZooKeeper就可以來解決這個問題

從節點失效

  • 類似的,在從節點失效時,主節點也要獲取從節點失效的信息,這些信息不能簡單地通過PING/PONG消息來獲取(因爲網絡可能有延遲),需要從其他地方獲取,例如ZooKeeper

六、演示案例:主-從應用(以HBase爲例)

  • 我們從理論上介紹了分佈式系統,現在,是時候讓它更具體⼀點了。 考慮在分佈式系統設計中⼀個得到⼴泛應⽤的架構:⼀個主-從(masterworker)架構(如下圖)。該系統中遵循這個架構的⼀個重要例⼦是HBase ——⼀個Google的數據存儲系統(BigTable)模型的實現,在最⾼層,主 節點服務器(HMaster)負責跟蹤區域服務器(HRegionServer)是否可 ⽤,並分派區域到服務器。因本書未涉及這些內容,如欲瞭解它如何使⽤ ZooKeeper等更多細節,建議查看HBase相關⽂檔。我們討論的焦點是⼀般 的主-從架構

  • ⼀般在這種架構中,主節點進程負責跟蹤從節點狀態和任務的有效 性,並分配任務到從節點。對ZooKeeper來說,這個架構風格具有代表性, 闡述了⼤多數流⾏的任務,如選舉主節點,跟蹤有效的從節點,維護應⽤ 元數據

主節點失效

  • 主節點失效時,我們需要有⼀個備份主節點(backup master)。當主 要主節點(primary master)崩潰時,備份主節點接管主要主節點的⾓⾊, 進⾏故障轉移,然⽽,這並不是簡單開始處理進⼊主節點的請求。新的主 要主節點需要能夠恢復到舊的主要主節點崩潰時的狀態。對於主節點狀態 的可恢復性,我們不能依靠從已經崩潰的主節點來獲取這些信息,⽽需要從其他地⽅獲取,也就是通過ZooKeeper來獲取
  • 狀態恢復並不是唯⼀的重要問題。假如主節點有效,備份主節點卻認 爲主節點已經崩潰。這種錯誤的假設可能發⽣在以下情況,例如主節點負 載很⾼,導致消息任意延遲,備份主節 點將會接管成爲主節點的⾓⾊,執⾏所有必需的程序,最終可能以主節點 的⾓⾊開始執⾏,成爲第⼆個主要主節點。更糟的是,如果⼀些從節點⽆ 法與主要主節點通信,如由於⽹絡分區(network partition)錯誤導致,這 些從節點可能會停⽌與主要主節點的通信,⽽與第⼆個主要主節點建⽴主從關係。針對這個場景中導致的問題,我們⼀般稱之爲腦裂(splitbrain):系統中兩個或者多個部分開始獨⽴⼯作,導致整體⾏爲不⼀致 性。我們需要找出⼀種⽅法來處理主節點失效的情況,關鍵是我們需要避 免發⽣腦裂的情況

從節點失效

  • 客戶端向主節點提交任務,之後主節點將任務派發到有效的從節點 中。從節點接收到派發的任務,執⾏完這些任務後會向主節點報告執⾏狀 態。主節點下⼀步會將執⾏結果通知給客戶端。
  • 如果從節點崩潰了,所有已派發給這個從節點且尚未完成的任務需要 重新派發。其中⾸要需求是讓主節點具有檢測從節點的崩潰的能⼒。主節 點必須能夠檢測到從節點的崩潰,並確定哪些從節點是否有效以便派發崩潰節點的任務。⼀個從節點崩潰時,從節點也許執⾏了部分任務,也許全 部執⾏完,但沒有報告結果。如果整個運算過程產⽣了其他作⽤,我們還 有必要執⾏某些恢復過程來清除之前的狀態。

通信故障

  • 如果⼀個從節點與主節點的⽹絡連接斷開,⽐如⽹絡分區(network partition)導致,重新分配⼀個任務可能會導致兩個從節點執⾏相同的任 務。如果⼀個任務允許多次執⾏,我們在進⾏任務再分配時可以不⽤驗證 第⼀個從節點是否完成了該任務。如果⼀個任務不允許,那麼我們的應⽤ 需要適應多個從節點執⾏相同任務的可能性。
  • 通信故障導致的另⼀個重要問題是對鎖等同步原語的影響。因爲節點 可能崩潰,⽽系統也可能⽹絡分區(network partition),鎖機制也會阻⽌ 任務的繼續執⾏。因此ZooKeeper也需要實現處理這些情況的機制。⾸先, 客戶端可以告訴ZooKeeper某些數據的狀態是臨時狀態(ephemeral);其 次,同時ZooKeeper需要客戶端定時發送是否存活的通知,如果⼀個客戶端 未能及時發送通知,那麼所有從屬於這個客戶端的臨時狀態的數據將全部 被刪除。通過這兩個機制,在崩潰或通信故障發⽣時,我們就可以預防客 戶端獨⽴運⾏⽽發⽣的應⽤宕機。
  • 回想⼀下之前討論的內容,如果我們不能控制系統中的消息延遲,就 不能確定⼀個客戶端是崩潰還是運⾏緩慢,因此,當我們猜測⼀個客戶端 已經崩潰,⽽實際上我們也需要假設客戶端僅僅是執⾏緩慢,其在後續還 可能執⾏⼀些其他操作
  • 任務總結,根據之前描述的這些,我們可以得到以下主-從架構的需求:
    • 主節點選舉:這是關鍵的⼀步,使得主節點可以給從節點分配任務。
    • 崩潰檢測:主節點必須具有檢測從節點崩潰或失去連接的能⼒。
    • 組成員關係管理:主節點必須具有知道哪⼀個從節點可以執⾏任務的能⼒。
    • 元數據管理:主節點和從節點必須具有通過某種可靠的⽅式來保存分配狀態和執⾏ 狀態的能⼒。

七、演示案例:服務發現上的負載均衡

  • 先來看一個例子,比如我們的一個遊戲服務系統是一個分佈式的系統,結構如下所示:

  • 裏面的GameServer在處理業務時需要調用DataServer的接口update數據,也就是說GameServer必須知道DataServer的IP地址和端口,常用的做法是把IP、Port寫入配置文件。例如:
<?xml version="1.0" encoding="UTF-8"?>
<root version="1.0">
    <!--GameServer監聽端口-->
    <HostServer type="1" id="1">
        <bind ip="192.168.1.134" port="8500" type="0" />
        <register ip="192.168.1.134" />
    </HostServer>

    <!--連接DataServer的端口-->
    <DataServer>
        <connect ip="192.168.1.135" port="8600" type ="0" />
    </DataServer>
 
    <RecvBuffer>
    <buf msgHeadLen="12" clientBuf="40960" serverBuf="1024000" />
    </RecvBuffer>   
</root>
  • 上面的處理看起來似乎沒有什麼問題,但是是有很多問題的:
    • 問題①:GameServer啓動的時候就去連接DataServer,連接並去發送消息可能沒有什麼問題,如果DataServer啓動時端口是監聽起來了,可是啓動後,發現DataServer中處理業務消息的某個模塊不可用。此時GameServer並不知道這個情況,反正已經開始發送業務消息給DataServer了。像這種情況,我們可以稱之爲“優雅發佈問題”
    • 問題②:遊戲服務整體已經可用了,但是研發內部說要整治下服務,需要重新梳理各個系統的IP配置,我們慣用做法還是去更新這個配置文件中的IP值,然後重啓GameServer使之生效,在這個過程中勢必導致GameServer的短暫不可用。重啓之後其他節點都需要停止並更新GameServer的信息,因此將信息寫死到配置文件的做法不可取。這樣一種情況,我們稱之爲“優雅更新配置問題”。當然增加DataServer的部署也會導致這個問題
    • 問題③:比如,在遊戲過程中,突然DataServer宕機了,或者DataServer應用崩潰了,導致對外不可用,那麼GameServer如何感知到,並且不再發送請求到DataServer呢?這個問題其實就是服務健康檢查,比如nginx也提供了健康檢查
  • 上面三個問題我們可以用服務發現的機制去解決,那麼什麼叫做服務主動發現以及如何設計實現呢?而且如果DataServer是一種異構的服務配置,也就是說它們的硬件配置不一樣,這樣GameServer就必須通過權重配比的方式去發送請求給多個DataServer。那利用ZooKeeper是怎麼做的呢?

八、分佈式協作的難點

  • 當開發分佈式應⽤時,其複雜性會⽴即突顯出來。例如,當我們的應 ⽤啓動後,所有不同的進程通過某種⽅法,需要知道應⽤的配置信息,⼀ 段時間之後,配置信息也許發⽣了變化,我們可以停⽌所有進程,重新分 發配置信息的⽂件,然後重新啓動,但是重新配置就會延長應⽤的停機時間
  • 與配置信息問題相關的是組成員關係的問題,當負載變化時,我們希 望增加或減少新機器和進程
  • 當你⾃⼰實現分佈式應⽤時,這個問題僅僅被描述爲功能性問題,你 可以設計解決⽅案,部署前你測試了你的解決⽅案,並⾮常確定地認爲你 已經正確解決了問題。當你在開發分佈式應⽤時,你就會遇到真正困難的 問題,你就不得不⾯對故障,如崩潰、通信故障等各種情況。這些問題會 在任何可能的點突然出現,甚⾄⽆法列舉需要處理的所有的情況

注意:拜占庭將軍問題

  • 拜占庭將軍問題(Byzantine Faults)是指可能導致⼀個組件發⽣任意 ⾏爲(常常是意料之外的)的故障。這個故障的組件可能會破壞應用的狀 態,甚⾄是惡意⾏爲。系統是建立在假設會發⽣這些故障,需要更⾼程度 的複製並使用安全原語的基礎上。儘管我們從學術⽂獻中知道,針對拜占庭將軍問題技術發展已經取得了巨⼤進步,我們還是覺得沒有必要在 ZooKeeper中採用這些技術,因此,我們也避免代碼庫中引⼊額外的複雜 性
  • 在獨⽴主機上運⾏的應⽤與分佈式應⽤發⽣的故障存在顯著的區別: 在分佈式應⽤中,可能會發⽣局部故障,當獨⽴主機崩潰,這個主機上運 ⾏的所有進程都會失敗,如果是獨⽴主機上運⾏多個進程,⼀個進程執⾏ 的失敗,其他進程可以通過操作系統獲得這個故障,操作系統提供了健壯 的多進程消息通信的保障。在分佈式環境中這⼀切發⽣了改變:如果⼀個 主機或進程發⽣故障,其他主機繼續運⾏,並會接管發⽣故障的進程,爲 了能夠處理故障進程,這些仍在運⾏的進程必須能夠檢測到這個故障,⽆ 論是消息丟失或發⽣了時間偏移。
  • 理想的情況下,我們基於異步通信的假設來設計系統,即我們使⽤的 主機有可能發⽣時間偏移或通信故障。我們做出這個假設是因爲這⼀切的 確會發⽣,時間偏移時常會發⽣,我們偶爾就會遇到⽹絡問題,甚⾄更不 幸的,發⽣故障。我們可以做什麼樣的限制呢?
  • 我們來看⼀個最簡單的情況。假設我們有⼀個分佈式的配置信息發⽣ 了改變,這個配置信息簡單到僅僅只有⼀個⽐特位(bit),⼀旦所有運⾏ 中的進程對配置位的值達成⼀致,我們應⽤中的進程就可以啓動。
  • 這個例⼦原本是⼀個在分佈式計算領域⾮常著名的定律,被稱爲 FLP(由其作者命名:Fischer,Lynch,Patterson),這個結論證明了在異步通信的分佈式系統中,進程崩潰,所有進程可能⽆法在這個⽐特位的配 置上達成⼀致。類似的定律稱爲CAP,表⽰⼀致性(Consistency)、可 ⽤性(Availability)和分區容錯性(Partition-tolerance),該定律指出,當 設計⼀個分佈式系統時,我們希望這三種屬性全部滿⾜,但沒有系統可以 同時滿⾜這三種屬性。因此ZooKeeper的設計儘可能滿⾜⼀致性和可⽤ 性,當然,在發⽣⽹絡分區時ZooKeeper也提供了只讀能⼒
  • 因此,我們⽆法擁有⼀個理想的故障容錯的、分佈式的、真實環境存 在的系統來處理可能發⽣的所有問題。但我們還是可以爭取⼀個稍微不那 麼宏偉的⽬標。⾸先,我們只好對我們的假設或⽬標適當放鬆,例如,我 們可以假設時鐘在某種範圍內是同步的,我們也可以犧牲⼀些⽹絡分區容 錯的能⼒並認爲其⼀直是⼀致的,當⼀個進程運⾏中,也許多次因⽆法確 定系統中的狀態⽽被認爲已經發⽣故障。雖然這些是⼀些折中⽅案,⽽這 些折中⽅案允許我們建⽴⼀些印象⾮常深刻的分佈式系統

九、ZooKeeper的成功和注意事項

  • 不得不指出,完美的解決⽅案是不存在的,我們重申ZooKeeper⽆法解決分佈式應⽤開發者⾯對的所有問題,⽽是爲開發者提供了⼀個優雅的框 架來處理這些問題。多年以來,ZooKeeper在分佈式計算領域進⾏了⼤量的⼯作。Paxos算法和虛擬同步技術(virtual synchrony)給ZooKeeper的設計帶來了很⼤影響,通過這些技術可以⽆縫地處理所發⽣的某些變化或情況,並提供給開發者⼀個框架,來應對⽆法⾃動處理的某些情況
  • ZooKeeper最初由雅虎研究院開發,⽤於處理⼤量的⼤型分佈式應⽤。 我們注意到,這些應⽤在分佈式協作⽅⾯的處理⽅式並不妥當,這些系統 的部署存在單點故障問題或很脆弱,另⼀⽅⾯,開發者在分佈式協作⽅⾯ 花費了⼤量的時間和精⼒,導致開發者沒有⾜夠的資源來關注應⽤本⾝的 功能邏輯。我們還注意到,這些應⽤都在基本協作⽅⾯有相同的需求。因 此,我們開始着⼿設計⼀套通⽤的解決⽅案,通過某些關鍵點讓我們可以 ⼀次實現就能應⽤於⼤多數不同的應⽤中。ZooKeeper已經被證實更加通 ⽤,其受歡迎程度超越了我們的想象
  • 多年來,我們發現⼈們可以很容易地部署ZooKeeper集羣,輕鬆通過這 個集羣開發應⽤,但實際上,在使⽤ZooKeeper時,有些情況ZooKeeper⾃⾝⽆法進⾏決策⽽是需要開發者⾃⼰做出決策,有些開發者並不完全瞭解這些
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章