ZooKeeper的應用場景(命名服務、分布式協調通知)

3 命名服務

命名服務(NameService)也是分布式系統中比較常見的一類場景,在《Java網絡高級編程》一書中提到,命名服務是分布式系統最基本的公共服務之一。在分布式系統中,被命名的實體通常可以是集群中的機器、提供的服務地址或遠程對象等一這些我們都可以統稱它們為名字(Name),其中較為常見的就是一些分布式服務框架(如RPC、RMI)中的服務地址列表,通過使用命名服務,客戶端應用能夠根據指定名字來獲取資源的實體、服務地址和提供者的信息等。

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

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

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

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

確實,UUID是一個非常不錯的全局唯一ID生成方式,能夠非常簡便地保證分布式環境中的唯一性。一個標準的UUID 是一個包含32位字符和4個短線的字符串,例如“e70f1357-f260-46ff-a32d-53a086c57ade”。UUID的優勢自然不必多說,我們重點來看看

它的缺陷。

(1)長度過長

UUID最大的問題就在于生成的字符串過長。顯然,和數據庫中的INT類型相比,存儲一個UUID需要花費更多的空間。

(2)含義不明

上面我們已經看到一個典型的UUID是類似于“e70f1357- f260-46fF- a32d-53a086c57ade"的一個字符串。根據這個字符串,開發人員從字面上基本看不出任何其表達的含義,這將會大大影響問題排查和開發調試的效率。

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

通過調用ZooKeeper節點創建的API接口可以創建一個順序節點,并且在API返回值中會返回這個節點的完整名字。利用這個特性,我們就可以借助ZooKeeper來生成全局唯一的ID了,如下圖所示。

結合上圖,我們來講解對于一個任務列表的主鍵,使用ZooKeeper生成唯一ID 的基本步驟。

(1)所有客戶端都會根據自己的任務類型,在指定類型的任務下面通過調用create()接口來創建一個順序節點,例如創建“job-”節點。

(2)節點創建完畢后,create()接口會返回一個完整的節點名,例如“job-000000003"。

(3)客戶端拿到這個返回值后,拼接上type類型,例如“type2-job 000000003”, 這就可以作為一個全局唯一的ID了。

在ZooKeeper中,每一個數據節點都能夠維護--份子節點的順序順列,當客戶端對其創建一個順序子節點的時候ZooKeeper會自動以后綴的形式在其子節點上添加一個序號,在這個場景中就是利用了ZooKeeper的這個特性。

4 分布式協調/通知

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

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

MySQL數據復制總線:Mysql_Replicator

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

?

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

Core實現了數據復制的核心邏輯,其將數據復制封裝成管道,并抽象出生產者和消費者兩個概念,其中生產者通常是MySQL數據庫的Binlog日志。

Server負責啟動和停止復制任務。

Monitor負責監控任務的運行狀態,如果在數據復制期間發生異常或出現故障會進行告警。

三個子模塊之間的關系如下圖所示。

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

任務注冊

Core進程在啟動的時候,首先會向/mysql_replicator/tasks節點(以下簡稱“任務列表節點”)注冊任務。例如,對于一個“復制熱門商品”的任務,Task 所在機器在啟動的時候,會首先在任務列表節點上創建一個子節點,例如/mysql_replicator/tasks/copy_hot_item(以下簡稱“任務節點")。如果在注冊過程中發現該子節點已經存在,說明已經有其他Task機器注冊了該任務,因此自己不需要再創建該節點了。

任務熱備份

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

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

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

熱備切換

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

記錄執行狀態

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

控制臺協調

在Mysql_Replicator中,Server主要的工作就是進行任務的控制,通過ZooKeeper來對不同的任務進行控制與協調。Server會將每個復制任務對應生產者的元數據,即庫名、表名、用戶名與密碼等數據庫信息以及消費者的相關信息以配置的形式寫入任務節點/mysql_replicator/tasks/copy_hot_item中去,以便該任務的所有任務機器都能夠共享該復制任務的配置。

冷備切換

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

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

冷熱備份對比

從上面的講解中,我們基本對熱備份和冷備份兩種運行方式都有了一定的了解,現在再來對比下這兩種運行方式。在熱備份方案中,針對一個任務使用了兩臺機器進行熱備份,借助ZooKeeper的Watcher通知機制和臨時順序節點的特性,能夠非常實時地進行互相協調,但缺陷就是機器資源消耗比較大。而在冷備份方案中,采用了掃描機制,雖然降低了任務協調的實時性,但是節省了機器資源。

一種通用的分布式系統機器間通信方式

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

心跳檢測

機器間的心跳檢測機制是指在分布式環境中,不同機器之間需要檢測到彼此是否在正常運行,例如A機器需要知道B機器是否正常運行。在傳統的開發中,我們通常是通過主機之間是否可以相互PING通來判斷,更復雜一點的話,則會通過在機器之間建立長連接,通過TCP連接固有的心跳檢測機制來實現上層機器的心跳檢測,這些確實都是一些非常常見的心跳檢測方法。

下面來看看如何使用ZooKeeper來實現分布式機器間的心跳檢測。基于ZooKeeper的臨時節點特性,可以讓不同的機器都在ZooKeeper的一個指定節點下創建臨時子節點,不同的機器之間可以根據這個臨時節點來判斷對應的客戶端機器是否存活。通過這種方式,檢測系統和被檢測系統之間并不需要直接相關聯,而是通過ZooKeeper上的某個節點進行關聯,大大減少了系統耦合。

工作進度匯報

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

通過判斷臨時節點是否存在來確定任務機器是否存活;

各個任務機器會實時地將自己的任務執行進度寫到這個臨時節點上去,以便中心系

統能夠實時地獲取到任務的執行進度。

系統調度

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

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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/39728.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/39728.shtml
英文地址,請注明出處:http://en.pswp.cn/news/39728.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

iOS申請證書(.p12)和描述文件(.mobileprovision)

打包app時,經常會用到ios證書,但很多人都苦于沒有蘋果電腦,即使有蘋果電腦的,也會覺得蘋果電腦操作也很麻煩,這里記錄一下,用香蕉云編,申請證書及描述文件的過程。 香蕉云編的地址:…

【C語言】每日一題(多數元素)

多數元素,鏈接奉上 方法 1.摩爾投票2.合理但錯誤的方法2.1暴力循環2.2排序求出中間元素中間元素 1.摩爾投票 先來簡單的介紹摩爾投票: 摩爾投票是一種用來解決絕對眾數問題的算法。 什么是絕對眾數呢? 在一個集合中,如果一個元素…

[國產MCU]-BL602開發實例-SPI與WS2812B驅動

SPI與WS2812B驅動 文章目錄 SPI與WS2812B驅動1、BL602的SPI介紹2、SPI驅動API介紹3、WS2812B介紹4、WS2812B的SPI驅動實現串行外設接口(Serial Peripheral Interface Bus,SPI)是一種用于短程通信的同步串行通信接口規范,設備之間使用全雙工模式通信,是一個主機和一個或多個…

每天一練:SpringBoot連接mq

目錄 每天一練:Springboot連接rabbitmq 每天一練:Springboot連接rabbitmq 目錄一、部署Rabbitmq?二、增加maven依賴三、連接RabbitMq四、發布和訂閱消息總結 一、部署Rabbitmq? 這里rabbitmq采用docker安裝部署。 拉取docker鏡像 [root192 ~]# docker…

【ChatGLM】ChatGLM-6B模型Win+4GB顯卡本地部署筆記

ChatGLM-6B是清華大學知識工程和數據挖掘小組發布的一個類似ChatGPT的開源對話機器人,由于該模型是經過約1T標識符的中英文訓練,且大部分都是中文,因此十分適合國內使用。 預期環境 本機電腦備注: Win10專業版 32G內存256固態系統…

ChatGPT 調教日記(二):程序員轉量化的背景知識

程序員如何學習量化金融 作為一個程序員學習量化金融(quant)是一個不錯的選擇。以下是一些建議: 學習金融基礎知識:了解金融市場、投資策略和金融產品。這將幫助你理解量化金融的背景和應用場景。 學習統計學和數學:…

FlutterBoost 實現Flutter頁面內嵌iOS view

在使用Flutter混合開發中會遇到一些原生比Flutter優秀的控件,不想使用Flutter的控件,想在Flutter中使用原生控件。這時就會用到 Flutter頁面中內嵌 原生view,這里簡單介紹一個 內嵌 iOS 的view。 注:這里使用了 FlutterBoost。網…

SAP動態安全庫存簡介

動態安全庫存:跑需求計劃時,ERP系統按設置的庫存方式自動計算出滿足一定時間內可保障生產的庫存數量 SAP動態安全庫存的計算公式:動態安全庫存=平均日需求*覆蓋范圍。 平均日需求=特定時期內的總需求/特定時期內的工作天數 覆蓋范圍指在沒又貨物供應的情況下,庫存可以維…

稀疏感知圖像和體數據恢復的系統對象研究(Matlab代碼實現)

💥💥💞💞歡迎來到本博客????💥💥 🏆博主優勢:🌞🌞🌞博客內容盡量做到思維縝密,邏輯清晰,為了方便讀者。 ??座右銘&a…

STM32 F103C8T6學習筆記6:IIC通信__驅動MPU6050 6軸運動處理組件—一階互補濾波

今日主要學習一款傾角傳感器——MPU6050,往后對單片機原理基礎講的會比較少,更傾向于簡單粗暴地貼代碼,因為經過前些日子對MSP432的學習,對原理方面也有些熟絡了,除了在新接觸它時會對其引腳、時鐘、總線等進行仔細一些的研究之外…

ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031)

安全之安全(security)博客目錄導讀 ATF(TF-A)安全通告匯總 目錄 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) 二、CVE-2017-15031 一、ATF(TF-A)安全通告 TFV-5 (CVE-2017-15031) Title 未初始化或保存/恢復PMCR_EL0可能會泄露安全世界的時間信息 CVE ID CVE-2017-1503…

101.for循環語句練習題-求數列前n項的平方和

【目錄】 文章目錄 101.for循環語句練習題-求數列前n項的平方和1. 求數列前n項的平方和2. 冪函數3. f 字符串格式化語法4. 基礎代碼5. 自定義函數代碼6. 遞歸函數代碼7. 代碼總結 【正文】 101.for循環語句練習題-求數列前n項的平方和 1. 求數列前n項的平方和 【目標任務】 …

spark的standalone 分布式搭建

一、環境準備 集群環境hadoop11,hadoop12 ,hadoop13 安裝 zookeeper 和 HDFS 1、啟動zookeeper -- 啟動zookeeper(11,12,13都需要啟動) xcall.sh zkServer.sh start -- 或者 zk.sh start -- xcall.sh 和zk.sh都是自己寫的腳本-- 查看進程 jps -- 有…

C++中配置OpenCV的教程

首先去OpenCV的官網下載OpenCV安裝包,選擇合適的平臺和版本進行下載,我下載的是Windows的OpenCV-4.7.0版本。OpenCV下載地址 下載好后,解壓到自己指定的路徑。 配置環境變量: WinR鍵打開運行窗口,輸入sysdm.cpl打開系…

星星之火:國產訊飛星火大模型的實際使用體驗(與GPT對比)

#AIGC技術內容創作征文|全網尋找AI創作者,快來釋放你的創作潛能吧!# 文章目錄 1 前言2 測試詳情2.1 文案寫作2.2 知識寫作2.3 閱讀理解2.4 語意測試(重點關注)2.5 常識性測試(重點關注)2.6 代碼…

常識判斷

頭像 carrin~👻 產品經理 225/753 75/302.5 30/152 15/101.5 等差數列,所以最后一個是10/101 收起 60 回復 發布于 2020-02-18 16:33

Mysql之explain詳解

1. explain作用 使用explain可以展示出sql語句的執行計劃,再根據sql的執行計劃去判斷這條sql有哪些點可以進行優化,從而讓sql的效率達到最大化。 2. 執行計劃各列含義 (1)id:id列是select的序列號,這個…

React18TS項目:配置react-css-modules,使用styleName

他的好處不說了 網上一堆文章一個能打的都沒有, 添加開發依賴 pnpm add -D dr.pogodin/babel-plugin-react-css-modules types/react-css-modules Babel Plugin "React CSS Modules" | Dr. Pogodin Studio 看dr.pogodin/babel-plugin-react-css-mo…

centos7安裝erlang及rabbitMQ

下載前注意事項: 第一:自己的系統版本,centos中uname -a指令可以查看,el8,el7,rabbitMQ的包不一樣! 第二:根據rabbitMQ中erlang version找到想要下載rabbitMQ對應erlang版本&#x…

封裝、繼承、多態

封裝是什么? 封裝是面向對象的特征之一,是對象和類概念的主要特性。 封裝,也就是把客觀事物封裝成抽象的類,并且類可以把自己的數據和方法只讓可信的類或者對象操作,對不可信的進行信息隱藏。 封裝,是把客觀…