Zookeeper的典型應用場景(1)

此文知識來自于:《從Paxos到Zookeeper分布式一致性原理與實踐》第六章

  1. 數(shù)據(jù)發(fā)布/訂閱(配置中心)
  2. 負載均衡(DNS解析)
  3. 命名服務(順序節(jié)點特性)
  4. 分布式協(xié)調/通知(Watcher機制)

1.1 數(shù)據(jù)發(fā)布/訂閱

數(shù)據(jù)發(fā)布/訂閱(Pulish/Subscribe)系統(tǒng),即所謂的配置中心,顧名思義就是發(fā)布者將數(shù)據(jù)發(fā)布到ZooKeeper的一個或一系列節(jié)點上,供訂閱者進行數(shù)據(jù)訂閱,
進而達到動態(tài)獲取數(shù)據(jù)的目的,實現(xiàn)配置信息的集中式管理和數(shù)據(jù)的動態(tài)更新。

發(fā)布/訂閱系統(tǒng)一般有兩種設計模式,分別是推(Push)模式和拉(Pull)模式。在推模式中,服務端主動將數(shù)據(jù)更新發(fā)送給所有訂閱的客戶端;而拉模式則是由
客戶端主動發(fā)起請求獲取最新數(shù)據(jù),通??蛻舳硕疾捎枚〞r進行輪詢拉取的方式。ZooKeeper采用的是推拉結合的方式:客戶端向服務端注冊自己需要關注的
節(jié)點,一旦該節(jié)點的數(shù)據(jù)發(fā)生變更,那么服務端就會向相應的客戶端發(fā)送Watcher事件通知,客戶端接收到這個消息通知之后,需要主動到服務端獲取最新的數(shù)據(jù)。

如果將配置信息存放到ZooKeeper上進行集中管理,那么通常情況下,應用在啟動的時候都會主動到ZooKeeper服務端上進行一次配置信息的獲取,同時,
在指定節(jié)點上注冊一個Watcher監(jiān)聽,這樣一來,但凡配置信息發(fā)生變更,服務端都會實時通知到所有訂閱的客戶端,從而達到實時獲取最新配置信息的目的。

實例:在我們平常的應用系統(tǒng)開發(fā)中,經(jīng)常會碰到這樣的需求:系統(tǒng)中需要使用一些通用的配置信息,例如機器列表信息、運行時的開關配置、數(shù)據(jù)庫配置信息等。
這些全局配置信息通暢具備以下3個特性:

  • 數(shù)據(jù)量通常比較小。
  • 數(shù)據(jù)內容在運行時會發(fā)生動態(tài)變化。
  • 集群中各機器共享,配置一致。

對于這類配置信息,一般的做法通??梢赃x擇將其存儲在本地配置文件或是內存變量中。本地配置可以采用JMX方式來實時對系統(tǒng)運行時內存變量的更新。

但是一旦機器規(guī)模變大,且配置信息變更頻繁后,就需要尋找一種更為分布式化的解決方案。

下面以“數(shù)據(jù)庫切換”的應用場景展開,看看如何使用ZooKeeper實現(xiàn)配置管理。

1.1.1 配置存儲

進行配置之前,首先初始化配置存儲到ZooKeeper上去,例如/app1/databse_config/(以下簡稱“配置節(jié)點”),寫入數(shù)據(jù)節(jié)點中:

dbcp.driverClassName=com.mysql.jdbc.Driver
dbcp.dbJDBCUrl=jdbc:mysql://localhost:3306/taokeeper
dbcp.characterEncoding=GBK
dbcp.username=admin
dbcp.password=root
dbcp.maxActive=30
dbcp.maxIdle=10
dbcp.maxWait=10000

1.1.2 配置獲取

集群中每臺機器在啟動初始化階段,首先會從上面提到的ZooKeeper配置節(jié)點上讀取數(shù)據(jù)庫信息,同時,客戶端還需要在該配置節(jié)點上注冊一個數(shù)據(jù)變更的
Water監(jiān)聽,一旦發(fā)生節(jié)點數(shù)據(jù)變更,所有訂閱的客戶端都能夠獲取到數(shù)據(jù)變更通知。

1.1.3 配置變更

在系統(tǒng)運行過程中,可能會出現(xiàn)需要機型數(shù)據(jù)庫切換的情況,借助ZooKeeper的Watcher機制,幫我們將數(shù)據(jù)變更的通知發(fā)送到各個客戶端,每個客戶端在
接收到這個變更通知后,就可以重新進行最新數(shù)據(jù)的獲取。

1.2 負載均衡

根據(jù)維基百科上的定義,負載均衡(Load Balance)是一種相當常見的計算機網(wǎng)絡技術,用來對多個計算機(計算機集群)、網(wǎng)絡連接、CPU、磁盤驅動器或是
其它資源進行分配負載,以達到優(yōu)化資源使用、最大化吞吐率、最小化響應時間和避免過載的目的。通常負載均衡可以分為硬件和軟件負載均衡兩種,本節(jié)
主要探討的是ZooKeeper在“軟”負載均衡中的應用場景。

在分布式系統(tǒng)中,負載均衡更是一種普遍的技術,基本上每一個分布式系統(tǒng)都需要使用負載均衡。在本書第一章講解分布式系統(tǒng)特征的時候,我們提到,分布式系統(tǒng)具有
對等性,為了保證系統(tǒng)的高可用性,通常采用副本的方式來對數(shù)據(jù)和服務進行部署。而對于消費者而言,則需要在這些對等的服務提供方中選擇一個來執(zhí)行相關的業(yè)務
邏輯,其中比較典型的就是DNS服務。在本節(jié)中,我們將詳細介紹如何使用ZooKeeper來解決負載均衡問題(請看深入分析Java_Web技術的第一章)。

1.2.1 一種動態(tài)的DNS服務

DNS是域名系統(tǒng)(Domain Name System)的縮寫。DNS系統(tǒng)可以看作是一個超大規(guī)模的分布式映射表,用于將域名和IP地址進行一一映射,進而方便人們
通過域名來訪問互聯(lián)網(wǎng)站點。

通常情況下,我們可以向域名注冊服務商申請域名注冊,但是這種方式最大的缺陷在于只能注冊有限的域名:

日常開發(fā)過程中,經(jīng)常會碰到這樣的情況,在一個Company1公司內部,需要給一個App1應用的服務器集群機器配置一個域名解析。相信有過一線開發(fā)
經(jīng)驗的讀者一定知道,這個時候通常需要由類似于app1.company1.com的一個域名,其對應的就是一個服務器地址。如果系統(tǒng)數(shù)量不多,那么通過
這種傳統(tǒng)的DNS配置方式還可以應付,但是,一旦公司規(guī)模變大,各類應用層出不窮,那么就很難再通過這種方式來進行統(tǒng)一的管理了。

因此,在實際開發(fā)中,往往使用本地HOST綁定來實現(xiàn)域名解析的工作。具體如何進行本地HOST綁定,因為不是本書的重點,并且互聯(lián)網(wǎng)上有大量額資料,
因此這里不再多說明。使用本地HOST綁定的方法,可以很容易解決域名緊張的問題,基本上每一個系統(tǒng)都可以自行確定系統(tǒng)的域名與目標IO地址。大大提高了
開發(fā)調試效率。(就是修改HOST文件,讓域名與IP直接映射,減去解析時間)然而,這種看上去完美的方案,也有其致命的缺陷:

當應用的機器規(guī)模在一定范圍內,并且域名的變更不是特別頻繁時,本地HOST綁定是非常高效且簡單的方式。然而一旦機器規(guī)模變大后,就常常
會碰到這樣的情況:我們在應用上線的時候,需要在應用的每臺機器上去綁定域名,但是在機器規(guī)模相當龐大的情況下,這種做法就相當不方便。
另外,如果想要臨時更新域名,還需要到每個機器上去逐個進行變更,更消耗大量時間,因此完全無法保證實時性。

現(xiàn)在,我們來介紹一種基于ZoKeeper實現(xiàn)的動態(tài)DNS方案(簡稱“DDNS”,Dynamic DNS)。

1.2.2 域名配置

首先需要在ZooKeeper上創(chuàng)建一個節(jié)點來進行域名配置。


這樣,在/DDNS/app1的節(jié)點上,將自己的域名配置上去,并支持多個IP

192.168.0.1:8080, 192.168.0.2:8080

1.2.3 域名解析

在傳統(tǒng)的DNS解析中,我們都不需要關系域名的解析過程,所有這些工作都交給了操作系統(tǒng)的域名和IP地址映射機制(本地HOST綁定)或是專門的域名解析
服務器(由域名注冊服務商提供)。因此,在這點上,DDNS方案和傳統(tǒng)的域名解析有很大的區(qū)別————在DDNS中,域名的解析過程都是由每一個應用自己負責的。
通常應用都會首先從域名節(jié)點中獲取一份IP地址和端口的配置,進行自行解析。同時,每個應用還會在域名節(jié)點上注冊一個數(shù)據(jù)變更Watcher監(jiān)聽,以便及時
收到域名變更的通知。

1.2.4 域名變更

在運行過程中,難免會碰上域名對應的IP地址或是端口變更,這個時候就需要進行域名變更操作。在DDNS中,我們只需要對指定的域名節(jié)點進行更新操作,
ZooKeeper就會向訂閱的客戶端發(fā)送這個事件通知,應用在接收到這個事件通知后,就會再次進行域名配置的獲取。

上面我們介紹了如何使用ZooKeeper來實現(xiàn)一種動態(tài)的DNS系統(tǒng)。通過ZooKeeper來實現(xiàn)動態(tài)DNS服務,一方面,可以避免域名數(shù)量無限增長帶來的集中式維護
的成本;另一方面,在域名變更的情況下,也能夠避免因逐臺機器更新本地HOST而帶來的繁瑣工作。

1.2.5 自動化的DNS服務

根據(jù)上面的講解,相信讀者基本上已經(jīng)能夠使用ZooKeeper來實現(xiàn)一個動態(tài)的DNS服務了。但是我們仔細看一下上面的實現(xiàn)就會發(fā)現(xiàn),在域名變更環(huán)節(jié)中,當
域名對應的I地址發(fā)生變更的時候,我們還是需要人為地介入去修改域名節(jié)點上的IP地址和端口。接下來我們看看下面這種使用ZooKeeper實現(xiàn)的更為自動化
的DNS服務。自動化的DNS服務系統(tǒng)主要是為了實現(xiàn)服務的自動化定位。


首先來介紹整個動態(tài)DNS系統(tǒng)的架構體系中比較重要的組件及其職責。

  • Register Cluster:負責域名的動態(tài)注冊。
  • Dispatcher Cluster:負責域名解析。
  • Scanner Cluster:負責檢測以及維護服務狀態(tài)(探測服務的可用性、屏蔽異常服務節(jié)點等)。
  • SDK:提供各種語言的系統(tǒng)接入?yún)f(xié)議,提供服務注冊以及查詢接口。
  • Monitor:負責收集服務信息以及對DDNS自身狀態(tài)的監(jiān)控。
  • Controller:后臺管理的Console,負責授權管理、流量控制、靜態(tài)配置服務和手動屏蔽服務等功能,運維人員在上面管理Register、Dispatcher和Scanner等Cluster。

整個系統(tǒng)的核心當然是ZooKeeper集群,負責數(shù)據(jù)的存儲以及一系列分布式協(xié)調。下面我們再來詳細地看下整個系統(tǒng)是如何運行的。在這個架構模型中,我們
將那些目標IP地址和端口抽象為服務的提供者,而那些需要使用域名解析的客戶端則被抽象成服務的消費者。

.1 域名注冊


域名注冊主要是針對服務提供者來說的。域名注冊過程可以簡單地概括為:每個服務提供者在啟動的過程中,都會把自己的域名信息注冊到Register Cluster中去。

  1. 服務提供者通過SDK提供的API接口,將域名、IP地址和端口發(fā)送給Register Cluster。例如,A機器用于提供serverA.xxx.com,于是它就向Register
    發(fā)送一個“域名->IP:PORT”的映射:“serverA.xxx.com->192.168.0.1:8080”。
  2. Register獲取到域名、IP地址和端口配置后,根據(jù)域名將信息寫入相對應的ZooKeeper域名節(jié)點中。

.2 域名解析

域名解析是針對服務消費者來說的,正好和域名注冊過程相反:服務消費者在使用域名的時候,會向Dispatcher發(fā)出域名解析請求。Dispatcher收到請求后,
會從ZooKeeper上的指定域名節(jié)點讀取相應的IP:PORT列表,通過一定的策略選取其中一個返回給前端應用。

.3 域名探測

域名探測是指DDNS系統(tǒng)需要對域名下所有注冊的IP地址和端口的可用性進行檢測,俗稱“健康度檢測”。健康度檢測一般有兩種方式,第一種是服務端主動發(fā)起健康度心跳
檢測,這種方式一般需要在服務端和客戶端之間建立起一個TCP長鏈接;第二種則是客戶端主動向服務端發(fā)起健康度心跳檢測。在DDNS架構中的域名探測,使用
的是服務提供者都會定時向Scanner進行狀態(tài)匯報(即第二種健康度檢測方式)的模式,即每個服務提供者后都會定時向Scanner匯報自己的狀態(tài)。

Scanner會負責記錄每個服務提供者最近一次的狀態(tài)匯報時間,一旦超過5秒沒有收到狀態(tài)匯報,那么就認為該IP地址和端口已經(jīng)不可用,于是開始進行域名
清理過程。在域名清理過程中,Scanner會在ZooKeeper中找到該域名對應的域名節(jié)點,然后將該IP地址和端口配置從節(jié)點內容中移除。

3.1 命名服務

命名服務(Name Service)也是分布式系統(tǒng)中比較常見的一類場景。在分布式系統(tǒng)中,被命名的實體通??梢允羌褐械臋C器、提供的服務地址或遠程對象等————
這些我們都可以統(tǒng)稱它們?yōu)槊郑∟ame),其中較為常見的就是一些分布式服務框架(如RPC、RMI)中的服務地址列表,通過使用命名服務,
客戶端應用能夠根據(jù)指定名字來獲取資源的實體、服務地址和提供者的信息等。

Java語言中的JNDI便是一種典型的命名服務。JNDI是Java命名與目錄接口(Java Naming and Directory Interface)的縮寫,是J2EE體系中重要的規(guī)范之一,
標準的J2EE容器都提供了對JNDI規(guī)范的實現(xiàn)。因此,在實際開發(fā)中,開發(fā)人員常常使用應用服務器自帶的JNDI實現(xiàn)來數(shù)據(jù)源的配置與管理————使用JNDI方式后,
開發(fā)人員可以完成不需要關心與數(shù)據(jù)庫相關的任何信息,包括數(shù)據(jù)庫類型、JDBC驅動類型以及數(shù)據(jù)庫賬號等。

ZooKeeper提供的命名服務功能與JNDI技術有相似的地方,都能夠幫助應用系統(tǒng)通過一個資源引用的方式來實現(xiàn)對資源的定位與使用。另外,廣義上命名服務
的資源定位都不是真正意義的實體資源————在分布式環(huán)境中,上層應用僅僅需要一個全局唯一的名字,類似于數(shù)據(jù)庫中的唯一主鍵。下面我們來看看如何使用
ZooKeeper來實現(xiàn)一套分布式全局唯一ID的分配機制。

所謂ID,就是一個能夠唯一標識某個對象的標識符。在我們熟悉的關系型數(shù)據(jù)庫中,各個表都需要一個主鍵來唯一標識每條數(shù)據(jù)庫記錄,這個主鍵就是這樣的唯一ID。
在過去的單庫單表型系統(tǒng)中,通常可以使用數(shù)據(jù)庫字段自帶的auto_increment屬性來自動為每條數(shù)據(jù)庫記錄生成一個唯一的ID,數(shù)據(jù)庫會保證生成的這個ID
在全局唯一。但是隨著數(shù)據(jù)庫數(shù)據(jù)規(guī)模的不斷增大,分庫分表隨之出現(xiàn),而auto_increment屬性僅能針對單一表中的記錄自動生成ID,因此在這種情況下,
就無法再依靠數(shù)據(jù)庫的auto_increment屬性來唯一標識一條記錄了。于是,我們必須尋求一種能夠在分布式環(huán)境下生成全局唯一ID的方法。

一說起全局唯一ID,相信讀者都會聯(lián)想到UUID。沒錯,UUID是通用唯一識別碼(Universally Unique Identifier)的簡稱,是一種在分布式系統(tǒng)中廣泛
使用的用于唯一標識元素的標準,最典型的實現(xiàn)是GUID(Globally Unique Identifier,全局唯一標識符),主流ORM框架Hibernate有對UUID的直接支持。

確實,UUID是一個非常不錯的全局唯一ID生成方式,能夠非常簡便地保證分布式環(huán)境中的唯一性。一個標準的UUID是一個包含32位字符和4個短線的字符串,
例如“asd321a-sd-sdwds321d5w4a2-w5e4w51d”。UUID的優(yōu)勢自然不必多說,我們重點來看看它的缺陷。

  • 長度過長:與數(shù)據(jù)庫中的INT類型相比,存儲一個UUID需要花費更多得空空間。
  • 含義不明:影響問題排查和開發(fā)調試的效率。

接下來,我們結合一個分布式任務調度系統(tǒng)來看看如何使用ZooKeeper來實現(xiàn)這類全局唯一ID的生成。

通過ZooKeeper節(jié)點創(chuàng)建的API接口可以創(chuàng)建一個順序節(jié)點,并且在API返回值中會返回這個節(jié)點的完整名字。利用這個特性,我們就可以借助ZooKeeper來生成
全局唯一的ID了。

  1. 所有客戶端都會根據(jù)自己的任務類型,在指定類型的任務下面通過調用create()接口創(chuàng)建一個順序節(jié)點,例如創(chuàng)建“job-”節(jié)點。
  2. 節(jié)點創(chuàng)建完畢后,create()接口會返回一個完整的節(jié)點名,例如“job-0000000003”。
  3. 客戶端拿到這個返回值后,拼接上type類型,例如“type2-job-0000000003”,這就可以作為一個全局唯一的ID了。

在ZooKeeper中,每一個數(shù)據(jù)節(jié)點都能夠維護一份子節(jié)點的順序順列,當客戶單對其創(chuàng)建一個順序子節(jié)點的時候ZooKeeper會自動以后綴的形式在其子節(jié)點上
添加一個序號,在這個場景中就是利用了ZooKeeper的這個特性。以下為博主測試:


另外如果子節(jié)點過多,導致連接讀取超時,可以適當提高配置中的initLimit以及syncLimit的數(shù)值(10倍也是可以的)。

4.1 分布式協(xié)調/通知

分布式協(xié)調/通知服務是分布系統(tǒng)不可缺少的環(huán)節(jié),是將不同的分布式組件有機結合起來的關鍵所在。對于一個在多臺機器上部署運行的應用而言,通常
需要一個協(xié)調者(Coordinator)來控制整個系統(tǒng)的運行流程,例如分布式事務的處理、機器間的互相協(xié)調等。同時,引入這樣一個協(xié)調者,便于將分布式協(xié)調的職責從
應用中分離出來,從而可以大大減少系統(tǒng)之間的耦合性,而且能夠顯著提高系統(tǒng)的可擴展性。

ZooKeeper中特有的Watcher注冊與異步通知機制,能夠很好地實現(xiàn)分布式環(huán)境下不同機器,甚至是不同系統(tǒng)之間的協(xié)調與通知,從而實現(xiàn)對數(shù)據(jù)變更的實時處理。
基于ZooKeeper實現(xiàn)分布式協(xié)調與通知功能,通常的做法是不同的客戶端都對ZooKeeper上同一個數(shù)據(jù)節(jié)點進行Watcher注冊,監(jiān)聽數(shù)據(jù)節(jié)點的變化(包括
數(shù)據(jù)節(jié)點本身及其子節(jié)點),如果數(shù)據(jù)節(jié)點發(fā)生變化,那么所有訂閱的客戶端都能夠接收到相應的Watcher通知,并做出相應的處理。

4.1.1 MySQL數(shù)據(jù)復制總線:MySQL_Replicator

MySQL數(shù)據(jù)復制總線(以下簡稱“復制總線”)是一個實時數(shù)據(jù)復制框架,用于在不同的MySQL數(shù)據(jù)庫實例之間進行異步數(shù)據(jù)復制和數(shù)據(jù)變化通知。整個系統(tǒng)是一個由
MySQL數(shù)據(jù)庫集群、消息隊列系統(tǒng)、任務管理監(jiān)控平臺以及ZooKeeper集群等組件共同構成的一個包含數(shù)據(jù)生產(chǎn)者、復制管道和數(shù)據(jù)消息者等部分的數(shù)據(jù)總線系統(tǒng)。


在該系統(tǒng)中,ZooKeeper主要負責進行一系列的分布式協(xié)調工作,在具體的實現(xiàn)上,根據(jù)功能將數(shù)據(jù)復制組件劃分為三個核心子模塊:Core、Server和Monitor,
每個模塊分別為一個單獨的進程,通過ZooKeeper進行數(shù)據(jù)交換。

  • Core實現(xiàn)了數(shù)據(jù)復制的核心邏輯,其將數(shù)據(jù)復制封裝成管道,并抽象出生產(chǎn)者和消費者兩個概念,其中生產(chǎn)者通常是MySQL數(shù)據(jù)庫的Binlog日志。
  • Server負責啟動和停止復制任務。
  • Monitor負責監(jiān)控任務的運行狀態(tài),如果在數(shù)據(jù)復制期間發(fā)生異常或出現(xiàn)故障會進行告警。

三個子模塊之間的關系如下圖:


每個模塊作為獨立的進程運行在服務端,運行時的數(shù)據(jù)和配置信息均保存在ZooKeeper上,Web控制臺通過ZooKeeper上的數(shù)據(jù)獲取到后臺進程的數(shù)據(jù),同時發(fā)布控制信息。

4.1.2 任務注冊

Core進程啟動的時候,首先會向/mysql_replicator/tasks節(jié)點(以下簡稱“任務列表節(jié)點”)注冊任務。例如,對于一個“復制熱門商品”的任務,Task
所在機器在啟動的時候,會首先在任務列表節(jié)點上創(chuàng)建一個子節(jié)點,例如/mysql_replicator/tasks/copy_hot_time(以下簡稱“任務節(jié)點”),如下圖:


如果在注冊過程中發(fā)現(xiàn)該子節(jié)點已經(jīng)存在,說明已經(jīng)有其他Task機器注冊了該任務,因此自己不需要再創(chuàng)建該節(jié)點了。

4.1.3 任務熱備份

為了應對復制任務故障或者復制任務所在主機故障,復制組件采用“熱備份”的容災方式,即將同一個復制任務部署在不同的主機上,我們稱這樣的機器為“任務機器”,
主、備任務機器通過ZooKeeper互相檢測運行健康狀況。

為了實現(xiàn)上述熱備方案,無論在第一步中是否創(chuàng)建了任務節(jié)點,每臺任務機器都需要在/mysql_replicator/tasks/copy_hot_item/instances節(jié)點上
將自己的主機名注冊上去。注意,這里注冊的節(jié)點類型很特殊,是一個臨時的順序節(jié)點。在注冊完這個子節(jié)點后,通常一個完整的節(jié)點名如下:
/mysql_replicator/tasks/copy_hot_item/instances/[Hostname]-1,其中最后的序列號就是臨時順序節(jié)點的精華所在。

在完成該子節(jié)點的創(chuàng)建后,每臺任務機器都可以獲取到自己創(chuàng)建的節(jié)點的完成節(jié)點名以及所有子節(jié)點的列表,然后通過對比判斷自己是否是所有子節(jié)點中序號最小的。
如果自己是序號最小的子節(jié)點,那么就將自己的運行狀態(tài)設置為RUNNING,其余的任務機器則將自己設置為STANDBY————我們將這樣的熱備份策略稱為“小序號優(yōu)先”策略。

4.1.4 熱備切換

完成運行狀態(tài)的標識后,任務的客戶端機器就能夠正常工作了,其中標記為RUNNING的客戶端機器進行正常的數(shù)據(jù)復制,而標記為STANDBY的客戶端機器則進入待命狀態(tài)。
這里所謂待命狀態(tài),就是說一旦標記為RUNNING的機器出現(xiàn)故障停止了任務執(zhí)行,那么就需要在所有標記為STANDBY的客戶端機器再次按照“小序號優(yōu)先”策略來
選出RUNNING機器來執(zhí)行,具體的做法就是標記為STANDBY的機器都需要在/mysql_replicator/tasks/copy_hot_item/instances節(jié)點上注冊一個
“子節(jié)點列表變更”的Watcher監(jiān)聽,用來訂閱所有任務執(zhí)行機器的變化情況————一旦RUNNING機器宕機與ZooKeeper斷開連接后,對應的節(jié)點就會消失,
于是其他機器也就接收到了這個變更通知,從而開始新一輪的RUNNING選舉。

4.1.5 記錄執(zhí)行狀態(tài)

既然使用了熱備份,那么RUNNING任務機器就需要將運行時的上下文狀態(tài)保留給STANDBY任務機器。在這個場景中,最主要的上下文狀態(tài)就是數(shù)據(jù)復制過程中的
一些進度信息,例如Binlog日志的消費位點,因此需要將這些信息保存到ZooKeeper上以便共享。在Mysql_Replicator的設計中,選擇了
/mysql_replicator/tasks/copy_hot_item/lastCommit作為Binlog日志消費位點的存儲節(jié)點,RUNNING任務機器會定時向這個節(jié)點寫入當前的Binlog日志消費位點。

4.1.6 控制臺協(xié)調

在上文中我們主要講解了Core組件是如何進行分布式任務協(xié)調的,接下來我們再看看Server是如何來管理Core組件的。在Mysql_Replicator中,Server主要的
工作就是進行任務的控制,通過ZooKeeper來對不同的任務進行控制與協(xié)調。Server會將每個復制任務對應生產(chǎn)者的元數(shù)據(jù),即庫名、表名、用戶名與密碼等數(shù)據(jù)庫信息以及
消費者的相關信息以配置的形式寫入任務節(jié)點/mysql_replicator/tasks/copy_hot_item中去的,以便該任務的所有任務機器都能夠共享該復制任務的配置。

4.1.7 冷備切換

到目前為止我們已經(jīng)基本了解了Mysql_Replicator的工作原理,現(xiàn)在再回過頭來看上面提到的熱備份。在該熱備份方案中,針對一個任務,都會至少分配兩臺
任務機器來進行熱備份,但是在一定規(guī)模的大型互聯(lián)網(wǎng)公司中,往往有許多MySQL實例需要進行數(shù)據(jù)復制,每個數(shù)據(jù)庫實例都會對應一個復制任務,
如果每個任務都進行雙機熱備份的話,那么顯然需要消耗太多的機器。

因此我們同時設計了一種冷備份,它和熱備份方案的不同點在于,對所有任務進行分組,如下:


和熱備份中比較大的區(qū)別在于,Core進程被配置了所屬Group(組)。舉個例子來說,假如一個Core進程被標記了group1,那么在Core進程啟動后,會到對應
的ZooKeeper group1節(jié)點下面獲取所有的Task列表,假如找到了任務“copy_hot_item”之后,就會遍歷這個Task列表的instances節(jié)點,但凡還沒有子節(jié)點的,
則會創(chuàng)建一個臨時的順序節(jié)點:/mysql_replicator/task-groups/group1/copy_hot_item/instances/[Hostname]-1————當然,在這個過程中,其它
Core進程也會在這個instances節(jié)點下創(chuàng)建類似的子節(jié)點。和熱備份中的“小序號優(yōu)先”策略一樣,順序小的Core進程將自己標記為RUNNING,不同之處在于,其它Core
進程則會自動將自己創(chuàng)建的子節(jié)點刪除,然后繼續(xù)遍歷下一個Task節(jié)點————我們將這樣的過程稱為“冷備份掃描”。就這樣,所有Core進程在一個掃描周期內不斷地對相應
的Group下面的Task進行冷備份掃描。整個過程如下圖:

4.1.8 冷熱備份對比

從上面的講解中,我們基本對熱備份和冷備份兩種運行方式都有了一定的了解,現(xiàn)在再來對比下這兩種運行方式。在熱備份方案中,針對一個任務使用了兩臺機器進行
熱備份,借助ZooKeeper的Watcher通知機制和臨時順序節(jié)點的特性,能夠非常實時地進行互相協(xié)調,但缺陷就是機器資源消耗比較大。而在冷備份方案中,采用了掃描機制,
雖然降低了任務協(xié)調的實時性,但是節(jié)省了機器資源。(博主總結冷備份與熱備份的區(qū)別在于,熱備份一個運行多個等待,冷備份在于一個運行,系統(tǒng)輪詢判斷是否有一個
在運行,只要有一個在運行就遍歷下個任務,如果一個都沒有在運行這個任務就讓自己運行
)。

4.1.9 一種通用的分布式系統(tǒng)機器間通信方式

在絕大部分的分布式系統(tǒng)中,系統(tǒng)機器間的通信無外乎心跳檢測、工作進度匯報和系統(tǒng)調度這三種類型。接下來,我們將圍繞這三種類型的機器通信講解
如何基于ZooKeeper去實現(xiàn)一種分布式系統(tǒng)間的通信方式。

.1 心跳監(jiān)測

機器間的心跳檢測機制是指在分布式環(huán)境中,不同機器之間需要檢測到彼此是否在正常運行,例如A機器需要知道B機器是否正常運行。在傳統(tǒng)的開發(fā)中,我們
通常是通過主機之間是否可以互相PING通來判斷,更復雜一點的話,則會通過在機器之間建立長連接,通過TCP連接固有的心跳檢測機制來實現(xiàn)上層機器的心跳檢測,
這些確實都是一些非常常見的心跳檢測方法。而ZooKeeper基于ZooKeeper的臨時節(jié)點特性,可以讓不同的機器都在ZooKeeper的一個指定節(jié)點下創(chuàng)建臨時子節(jié)點,不同的機器
之間可以根據(jù)這個臨時節(jié)點來判斷對應的客戶端機器是否存活。通過這種方式,檢測系統(tǒng)和被檢測系統(tǒng)之間并不需要直接相關聯(lián),而是通過ZooKeeper上的
某個節(jié)點進行關聯(lián),大大減少了系統(tǒng)耦合。

.2 工作進度匯報

在一個常見的任務分發(fā)系統(tǒng)中,通常任務被分發(fā)到不同的機器上執(zhí)行后,需要實時地將自己的任務執(zhí)行進度匯報給分發(fā)系統(tǒng)。這個時候就可以通過ZooKeeper來實現(xiàn)。
在ZooKeeper上選擇一個節(jié)點,每個任務客戶端都在這個節(jié)點下面創(chuàng)建臨時子節(jié)點,這樣便可以實現(xiàn)兩個功能:

  • 通過判斷臨時節(jié)點是否存在來確定任務機器是否存活;
  • 各個任務機器會實時地將自己的任務執(zhí)行進度寫到這個臨時節(jié)點上去,以便中心系統(tǒng)能夠實時地獲取到任務的執(zhí)行進度。

.3 系統(tǒng)調度

使用ZooKeeper,能夠實現(xiàn)另一種調度模式:一個分布式系統(tǒng)由控制臺和一些客戶端系統(tǒng)兩部分組成,控制臺的職責就是需要將一些指令信息發(fā)送給所有的
客戶端,以控制它們進行相應的業(yè)務邏輯。后臺管理人員在控制臺上做的一些操作,實際上就是修改了ZooKeeper上某些節(jié)點的數(shù)據(jù),而ZooKeeper進一步
把這些數(shù)據(jù)變更以事件通知的形式發(fā)送給了對應的訂閱客戶端。

總之,使用ZooKeeper來實現(xiàn)分布式系統(tǒng)機器間的通信,不僅能省去大量底層網(wǎng)絡通信和協(xié)議設計上重復的工作,更為重要的一點是大大降低了系統(tǒng)之間的耦合,
能夠非常方便地實現(xiàn)異構系統(tǒng)之間的靈活通信。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,693評論 19 139
  • 此文知識來自于:《從Paxos到Zookeeper分布式一致性原理與實踐》第六章 集群管理(子節(jié)點) Master...
    李文文丶閱讀 707評論 0 1
  • 一、ZooKeeper的背景 1.1 認識ZooKeeper ZooKeeper---譯名為“動物園管理員”。動物...
    algernoon閱讀 9,353評論 1 106
  • 入冬,娘來電話囑咐穿棉褲,閑聊幾句后俺問到,三爺爺家的春花姑還瘋嗎?娘說,不瘋了,跟好人一樣。我追問,這回真不瘋了...
    才蛋閱讀 860評論 15 13
  • 最美好的愛情就是當我們都白發(fā)蒼蒼,你待我還像當初一樣[心]
    Mr_崇閱讀 259評論 0 1

友情鏈接更多精彩內容