日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪(fǎng)問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

Zookeeper的典型应用场景(1)

發(fā)布時(shí)間:2024/4/13 编程问答 43 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Zookeeper的典型应用场景(1) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

  • 數(shù)據(jù)發(fā)布/訂閱(配置中心)
  • 負(fù)載均衡(DNS解析)
  • 命名服務(wù)(順序節(jié)點(diǎn)特性)
  • 分布式協(xié)調(diào)/通知(Watcher機(jī)制)

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

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

    發(fā)布/訂閱系統(tǒng)一般有兩種設(shè)計(jì)模式,分別是推(Push)模式和拉(Pull)模式。在推模式中,服務(wù)端主動(dòng)將數(shù)據(jù)更新發(fā)送給所有訂閱的客戶(hù)端;而拉模式則是由
    客戶(hù)端主動(dòng)發(fā)起請(qǐng)求獲取最新數(shù)據(jù),通常客戶(hù)端都采用定時(shí)進(jìn)行輪詢(xún)拉取的方式。ZooKeeper采用的是推拉結(jié)合的方式:客戶(hù)端向服務(wù)端注冊(cè)自己需要關(guān)注的
    節(jié)點(diǎn),一旦該節(jié)點(diǎn)的數(shù)據(jù)發(fā)生變更,那么服務(wù)端就會(huì)向相應(yīng)的客戶(hù)端發(fā)送Watcher事件通知,客戶(hù)端接收到這個(gè)消息通知之后,需要主動(dòng)到服務(wù)端獲取最新的數(shù)據(jù)。

    如果將配置信息存放到ZooKeeper上進(jìn)行集中管理,那么通常情況下,應(yīng)用在啟動(dòng)的時(shí)候都會(huì)主動(dòng)到ZooKeeper服務(wù)端上進(jìn)行一次配置信息的獲取,同時(shí),
    在指定節(jié)點(diǎn)上注冊(cè)一個(gè)Watcher監(jiān)聽(tīng),這樣一來(lái),但凡配置信息發(fā)生變更,服務(wù)端都會(huì)實(shí)時(shí)通知到所有訂閱的客戶(hù)端,從而達(dá)到實(shí)時(shí)獲取最新配置信息的目的。

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

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

    對(duì)于這類(lèi)配置信息,一般的做法通常可以選擇將其存儲(chǔ)在本地配置文件或是內(nèi)存變量中。本地配置可以采用JMX方式來(lái)實(shí)時(shí)對(duì)系統(tǒng)運(yùn)行時(shí)內(nèi)存變量的更新。

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

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

    1.1.1 配置存儲(chǔ)

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

    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 配置獲取

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

    1.1.3 配置變更

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

    1.2 負(fù)載均衡

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

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

    1.2.1 一種動(dòng)態(tài)的DNS服務(wù)

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

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

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

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

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

    現(xiàn)在,我們來(lái)介紹一種基于ZoKeeper實(shí)現(xiàn)的動(dòng)態(tài)DNS方案(簡(jiǎn)稱(chēng)“DDNS”,Dynamic DNS)。

    1.2.2 域名配置

    首先需要在ZooKeeper上創(chuàng)建一個(gè)節(jié)點(diǎn)來(lái)進(jìn)行域名配置。


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

    ?

    192.168.0.1:8080, 192.168.0.2:8080

    1.2.3 域名解析

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

    1.2.4 域名變更

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

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

    1.2.5 自動(dòng)化的DNS服務(wù)

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


    首先來(lái)介紹整個(gè)動(dòng)態(tài)DNS系統(tǒng)的架構(gòu)體系中比較重要的組件及其職責(zé)。

    ?

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

    整個(gè)系統(tǒng)的核心當(dāng)然是ZooKeeper集群,負(fù)責(zé)數(shù)據(jù)的存儲(chǔ)以及一系列分布式協(xié)調(diào)。下面我們?cè)賮?lái)詳細(xì)地看下整個(gè)系統(tǒng)是如何運(yùn)行的。在這個(gè)架構(gòu)模型中,我們
    將那些目標(biāo)IP地址和端口抽象為服務(wù)的提供者,而那些需要使用域名解析的客戶(hù)端則被抽象成服務(wù)的消費(fèi)者。

    .1 域名注冊(cè)

    ?


    域名注冊(cè)主要是針對(duì)服務(wù)提供者來(lái)說(shuō)的。域名注冊(cè)過(guò)程可以簡(jiǎn)單地概括為:每個(gè)服務(wù)提供者在啟動(dòng)的過(guò)程中,都會(huì)把自己的域名信息注冊(cè)到Register Cluster中去。

    ?

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

    域名解析是針對(duì)服務(wù)消費(fèi)者來(lái)說(shuō)的,正好和域名注冊(cè)過(guò)程相反:服務(wù)消費(fèi)者在使用域名的時(shí)候,會(huì)向Dispatcher發(fā)出域名解析請(qǐng)求。Dispatcher收到請(qǐng)求后,
    會(huì)從ZooKeeper上的指定域名節(jié)點(diǎn)讀取相應(yīng)的IP:PORT列表,通過(guò)一定的策略選取其中一個(gè)返回給前端應(yīng)用。

    .3 域名探測(cè)

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

    Scanner會(huì)負(fù)責(zé)記錄每個(gè)服務(wù)提供者最近一次的狀態(tài)匯報(bào)時(shí)間,一旦超過(guò)5秒沒(méi)有收到狀態(tài)匯報(bào),那么就認(rèn)為該IP地址和端口已經(jīng)不可用,于是開(kāi)始進(jìn)行域名
    清理過(guò)程。在域名清理過(guò)程中,Scanner會(huì)在ZooKeeper中找到該域名對(duì)應(yīng)的域名節(jié)點(diǎn),然后將該IP地址和端口配置從節(jié)點(diǎn)內(nèi)容中移除。

    3.1 命名服務(wù)

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

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

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

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

    一說(shuō)起全局唯一ID,相信讀者都會(huì)聯(lián)想到UUID。沒(méi)錯(cuò),UUID是通用唯一識(shí)別碼(Universally Unique Identifier)的簡(jiǎn)稱(chēng),是一種在分布式系統(tǒng)中廣泛
    使用的用于唯一標(biāo)識(shí)元素的標(biāo)準(zhǔn),最典型的實(shí)現(xiàn)是GUID(Globally Unique Identifier,全局唯一標(biāo)識(shí)符),主流ORM框架Hibernate有對(duì)UUID的直接支持。

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

    • 長(zhǎng)度過(guò)長(zhǎng):與數(shù)據(jù)庫(kù)中的INT類(lèi)型相比,存儲(chǔ)一個(gè)UUID需要花費(fèi)更多得空空間。
    • 含義不明:影響問(wèn)題排查和開(kāi)發(fā)調(diào)試的效率。

    接下來(lái),我們結(jié)合一個(gè)分布式任務(wù)調(diào)度系統(tǒng)來(lái)看看如何使用ZooKeeper來(lái)實(shí)現(xiàn)這類(lèi)全局唯一ID的生成。

    通過(guò)ZooKeeper節(jié)點(diǎn)創(chuàng)建的API接口可以創(chuàng)建一個(gè)順序節(jié)點(diǎn),并且在A(yíng)PI返回值中會(huì)返回這個(gè)節(jié)點(diǎn)的完整名字。利用這個(gè)特性,我們就可以借助ZooKeeper來(lái)生成
    全局唯一的ID了。

    ?

  • 所有客戶(hù)端都會(huì)根據(jù)自己的任務(wù)類(lèi)型,在指定類(lèi)型的任務(wù)下面通過(guò)調(diào)用create()接口創(chuàng)建一個(gè)順序節(jié)點(diǎn),例如創(chuàng)建“job-”節(jié)點(diǎn)。
  • 節(jié)點(diǎn)創(chuàng)建完畢后,create()接口會(huì)返回一個(gè)完整的節(jié)點(diǎn)名,例如“job-0000000003”。
  • 客戶(hù)端拿到這個(gè)返回值后,拼接上type類(lèi)型,例如“type2-job-0000000003”,這就可以作為一個(gè)全局唯一的ID了。
  • 在ZooKeeper中,每一個(gè)數(shù)據(jù)節(jié)點(diǎn)都能夠維護(hù)一份子節(jié)點(diǎn)的順序順列,當(dāng)客戶(hù)單對(duì)其創(chuàng)建一個(gè)順序子節(jié)點(diǎn)的時(shí)候ZooKeeper會(huì)自動(dòng)以后綴的形式在其子節(jié)點(diǎn)上
    添加一個(gè)序號(hào),在這個(gè)場(chǎng)景中就是利用了ZooKeeper的這個(gè)特性。以下為博主測(cè)試:


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

    ?

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

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

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

    4.1.1 MySQL數(shù)據(jù)復(fù)制總線(xiàn):MySQL_Replicator

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


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

    ?

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

    三個(gè)子模塊之間的關(guān)系如下圖:


    每個(gè)模塊作為獨(dú)立的進(jìn)程運(yùn)行在服務(wù)端,運(yùn)行時(shí)的數(shù)據(jù)和配置信息均保存在ZooKeeper上,Web控制臺(tái)通過(guò)ZooKeeper上的數(shù)據(jù)獲取到后臺(tái)進(jìn)程的數(shù)據(jù),同時(shí)發(fā)布控制信息。

    ?

    4.1.2 任務(wù)注冊(cè)

    Core進(jìn)程啟動(dòng)的時(shí)候,首先會(huì)向/mysql_replicator/tasks節(jié)點(diǎn)(以下簡(jiǎn)稱(chēng)“任務(wù)列表節(jié)點(diǎn)”)注冊(cè)任務(wù)。例如,對(duì)于一個(gè)“復(fù)制熱門(mén)商品”的任務(wù),Task
    所在機(jī)器在啟動(dòng)的時(shí)候,會(huì)首先在任務(wù)列表節(jié)點(diǎn)上創(chuàng)建一個(gè)子節(jié)點(diǎn),例如/mysql_replicator/tasks/copy_hot_time(以下簡(jiǎn)稱(chēng)“任務(wù)節(jié)點(diǎn)”),如下圖:


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

    ?

    4.1.3 任務(wù)熱備份

    為了應(yīng)對(duì)復(fù)制任務(wù)故障或者復(fù)制任務(wù)所在主機(jī)故障,復(fù)制組件采用“熱備份”的容災(zāi)方式,即將同一個(gè)復(fù)制任務(wù)部署在不同的主機(jī)上,我們稱(chēng)這樣的機(jī)器為“任務(wù)機(jī)器”,
    主、備任務(wù)機(jī)器通過(guò)ZooKeeper互相檢測(cè)運(yùn)行健康狀況。

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

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

    4.1.4 熱備切換

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

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

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

    4.1.6 控制臺(tái)協(xié)調(diào)

    在上文中我們主要講解了Core組件是如何進(jìn)行分布式任務(wù)協(xié)調(diào)的,接下來(lái)我們?cè)倏纯碨erver是如何來(lái)管理Core組件的。在Mysql_Replicator中,Server主要的
    工作就是進(jìn)行任務(wù)的控制,通過(guò)ZooKeeper來(lái)對(duì)不同的任務(wù)進(jìn)行控制與協(xié)調(diào)。Server會(huì)將每個(gè)復(fù)制任務(wù)對(duì)應(yīng)生產(chǎn)者的元數(shù)據(jù),即庫(kù)名、表名、用戶(hù)名與密碼等數(shù)據(jù)庫(kù)信息以及
    消費(fèi)者的相關(guān)信息以配置的形式寫(xiě)入任務(wù)節(jié)點(diǎn)/mysql_replicator/tasks/copy_hot_item中去的,以便該任務(wù)的所有任務(wù)機(jī)器都能夠共享該復(fù)制任務(wù)的配置。

    4.1.7 冷備切換

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

    因此我們同時(shí)設(shè)計(jì)了一種冷備份,它和熱備份方案的不同點(diǎn)在于,對(duì)所有任務(wù)進(jìn)行分組,如下:


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

    ?

    4.1.8 冷熱備份對(duì)比

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

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

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

    .1 心跳監(jiān)測(cè)

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

    .2 工作進(jìn)度匯報(bào)

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

    • 通過(guò)判斷臨時(shí)節(jié)點(diǎn)是否存在來(lái)確定任務(wù)機(jī)器是否存活;
    • 各個(gè)任務(wù)機(jī)器會(huì)實(shí)時(shí)地將自己的任務(wù)執(zhí)行進(jìn)度寫(xiě)到這個(gè)臨時(shí)節(jié)點(diǎn)上去,以便中心系統(tǒng)能夠?qū)崟r(shí)地獲取到任務(wù)的執(zhí)行進(jìn)度。

    .3 系統(tǒng)調(diào)度

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

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



    作者:李文文丶
    鏈接:https://www.jianshu.com/p/52ed785f1d07
    來(lái)源:簡(jiǎn)書(shū)
    簡(jiǎn)書(shū)著作權(quán)歸作者所有,任何形式的轉(zhuǎn)載都請(qǐng)聯(lián)系作者獲得授權(quán)并注明出處。

    超強(qiáng)干貨來(lái)襲 云風(fēng)專(zhuān)訪(fǎng):近40年碼齡,通宵達(dá)旦的技術(shù)人生

    總結(jié)

    以上是生活随笔為你收集整理的Zookeeper的典型应用场景(1)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。