Zookeeper學習筆記(一)基本概念和簡單使用

北冥有隻魚發表於2022-06-26
閒扯兩句, 一般學習一門新技術我現在會直接看文件,文件上的一些核心觀點放到文章中,原因在於我希望記錄我的思考過程,同時也是鍛鍊自己閱讀英文文件的能力。

概述

首先我們開啟bing搜尋引擎,搜尋Zookeeper,有同學可能會問,你為什麼讓開啟bing搜素引擎,而不是百度呢。那是因為目前在百度搜尋Zookeeper,第一頁沒找到官網:

百度的搜尋結果

百度第二頁

但是你開啟bing搜尋Zookeeper:

bing的搜尋結果

個人感覺百度的搜尋質量有變差的跡象,所以我最近用bing比較多。

Zookeeper文件

bird

ZooKeeper is a high-performance coordination service for distributed applications. It exposes common services - such as naming, configuration management, synchronization, and group services - in a simple interface so you don't have to write them from scratch.

Zookeeper為分散式應用提供高效能協調服務,用簡單的介面提供了許多服務,有域名服務、配置管理、分散式同步、組服務。

解讀1: 域名服務、配置管理、分散式同步、組服務這四個似懂非懂.

解讀2 為分散式應用提供了高效能的協調服務,高效能我們是喜歡的,協調了啥?

再聊聊分散式吧

我們再來聊聊服務端系統架構的演進吧,最初的時候我們的服務只在一臺伺服器上執行,慢慢的隨著使用者量的不斷提升,單機部署已經無法再滿足訪問量了。於是人們自然就想到了叢集,即相同的應用再部署一遍,由Nginx或其他中介軟體根據負載均衡演算法將請求分攤到叢集的機器上。但是為了追求高可靠,我們不能將一個做單機叢集,將應用在配置檔案中改埠實現叢集,但是這並不可靠,假如這臺計算機出現了什麼問題,整個服務都會變得不可用,為了不讓雞蛋放在一個籃子裡,維持服務的高可靠,我們將服務在多臺計算機上,這樣就算一臺計算機上的服務出現了問題,服務還是可用的(現在我們的服務還是一個單體應用),這也就是分散式部署,所以分散式並不一定要和微服務掛鉤。

單機部署到叢集部署

但是這又引入了新的問題:

  • 一個節點掛掉不能提供服務時如何被叢集知曉並由其他節點接替任務
例子: 當資料量與訪問量不斷上升,單機的MySQL無法再支撐系統的訪問量,我們開始搭建叢集,提升資料庫的訪問能力,為了增加可靠性,我們多機部署,甚至多地部署。

資料庫叢集

一般來說增刪改消耗的效能遠小於查詢的效能,所以我們選若干臺資料庫節點做寫入,對於使用者的新增資料請求,會分攤到寫節點,寫節點寫入完成要將這個資料擴散到其他節點, 但這裡有一個問題就是如果寫節點掛掉呢,那一個自然而然的操作是從從庫中再選一個讀庫回應請求,同時將掛掉的結點從叢集中剔除.

  • 在分散式的場景下如何保證任務只被執行一次。
例子: 分散式下的定時任務,在計算機A和B上都部署了服務,如何保證定時任務只執行一次。

這也就是Zookeeper的協調。

基本概念與設計目標

在設計目標裡面能看到核心概念。
  • ZooKeeper is simple. (Zookeeper 是簡單的)

ZooKeeper allows distributed processes to coordinate with each other through a shared hierarchical namespace which is organized similarly to a standard file system. The namespace consists of data registers - called znodes, in ZooKeeper parlance - and these are similar to files and directories. Unlike a typical file system, which is designed for storage, ZooKeeper data is kept in-memory, which means ZooKeeper can achieve high throughput and low latency numbers.

Zookeeper通過類似於檔案系統的名稱空間來實現對分散式程式的協調,名稱空間是由一個一個資料暫存器組成,在Zookeeper中它們被稱為znode, ZNode與檔案系統的資料夾是相似的,但是Zookeeper選擇將資料儲存在記憶體中,這意味著Zookeeper可以實現高吞吐和低延遲。

Zookeeper的名稱空間

這就是Zookeeper的名稱空間,像不像Linux的檔案系統, 一個典型的樹結構, 其實你也可以類比到windows的檔案系統,/是根目錄,這是硬碟,下面是資料夾。像一個資料夾有多個子資料夾一樣,一個znode也擁有多個結點,以key/value形式儲存資料。Znode有兩種,分為臨時節點和永久節點,節點的型別在建立時被確定,並且不能改變。 臨時節點的生命週期依賴於建立它們的會話。一旦會話結束,臨時節點將會被自動刪除,當然也可以手動刪除,臨時節點不允許擁有子節點。永久節點的生命週期不依賴於會話,並且只有在客戶端顯式執行刪除操作的時候,才能被刪除。Znode還有一個序列化的特性,如果建立的時候指定的話,該Znode的名字後面會自動追加一個遞增的序列號。序列號對於此節點的父節點來說是唯一的,這樣便會記錄每個子節點的建立的先後順序。

Znode節點的特性:

  1. 兼具檔案和目錄特點 既像檔案一樣維護著資料、資訊、時間戳等資料,又像目錄一樣可以作為路徑標識的一部分,並可以具備子Znode。使用者對Znode具有增、刪、改、查等操作
  2. Znode具有原子性操作 讀操作將獲取與節點相關的所有資料,寫操作也將替換節點的所有資料
  3. Znode 儲存資料大小有限制 每個Znode的資料大小至多1M,但是常規使用中應該遠小於此值。
  4. Znode 通過路徑引用,路徑必須是絕對的。

  • ZooKeeper is replicated

    Like the distributed processes it coordinates, ZooKeeper itself is intended to be replicated over a set of hosts called an ensemble.

    The servers that make up the ZooKeeper service must all know about each other. They maintain an in-memory image of state, along with a transaction logs and snapshots in a persistent store. As long as a majority of the servers are available, the ZooKeeper service will be available.
    Clients connect to a single ZooKeeper server. The client maintains a TCP connection through which it sends requests, gets responses, gets watch events, and sends heart beats. If the TCP connection to the server breaks, the client will connect to a different server.

    如同被其協調的分散式應用一樣,Zookeeper本身也維持了一致性,叢集中的Zookeeper同步記憶體狀態、以及持久化的日誌和快照,只要大部分的伺服器是可用的,那麼對應的Zookeeper就是可用的。

    客戶端連線到單臺Zookeeper,通過該連線傳送請求、獲取響應、獲取監聽事件併傳送心跳,如果客戶端的連線斷開,客戶端將會連線到其他的Zookeeper上。

zkservice

  • Conditional updates and watches

    ZooKeeper supports the concept of watches. Clients can set a watch on a znode. A watch will be triggered and removed when the znode changes. When a watch is triggered, the client receives a packet saying that the znode has changed.

    Zookeeper 支援監聽的概念,客戶端可以監聽Znode,當節點被移除或者改變的時候,會通知監聽的客戶端,當節點發生改變的時候將收到訊息。

小小總結一下

Zookeeper藉助以上特性來實現上面我們提到的功能特性:

  • 域名服務 將ip對映為服務名,如果我們的服務叢集中需要互相呼叫,那麼我們可以選擇將ip和域名儲存到Zookeeper的節點中,在需要呼叫的時候去用域名來換取到對應的ip地址
  • 配置管理 動態重新整理配置, 基於監聽機制,我們將配置檔案儲存在Znode中,應用監聽對應的Znode,Znode改變會將改變推送給對應的應用。也就是動態重新整理配置
  • 資料的釋出與訂閱 同樣是基於監聽機制
  • 分散式鎖 不同主機上的程式競爭統一資源,可以藉助Zookeeper做分散式鎖,舉一個例子在服務A身上配置的有定時任務,我們叢集部署為了保證定時任務A只在一臺上跑,我們可以藉助分散式鎖來完成這個任務。

    為了讓我們讓我們的服務實現更強的吞吐能力和高可用,我們選擇了分散式部署,但是在計算機的世界裡通常是通過某種技術手段解決一個問題,就會引入新的問題,分散式部署的過程中,我們又遇到了新的問題,比如節點之間的協調(主從叢集中選中Leader),資源的競爭問題,為了解決這些問題Zookeeper應運而生。

    為什麼會將Zookeeper的官方文件拎出來呢,因為希望將自己的學習過程也記錄下來,我記得剛學Java Web的時候會去B站上找視訊,但是我看視訊的時候有的時候會想,視訊作者是怎麼得出這個結論的,他們是怎麼得出Zookeeper可以這麼用的,因為我想直接獲取第一手的資料,有自己的思考過程。

先裝起來

說了這麼多,我們先將zookeeper用起來再說。

Zookeeper下載

本次我們通過在Linux下進行安裝部署, 國內進入Zookeeper官網下載比較慢,我們通過映象進行下載:

# 首先在cd 到usr下建zookeeper目錄,然後在這個目錄下建zk1、zk2、zk3.我們本次做叢集部署
# zk1 下面執行下面命令 
wget https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz --no-check-certificate 
# 解壓
tar -xzvf apache-zookeeper-3.7.1-bin.tar.gz
# 然後建立data logs  目錄
mkdir data logs
# 將zk1 下面的所有檔案複製到 zk2 zk3 下面一份
cp -r /usr/zookeeper/zk1/*  /usr/zookeeper/zk2/
cp -r /usr/zookeeper/zk1/*  /usr/zookeeper/zk3/
# zk1/data 下面建立myud 檔案,此檔案記錄節點id,每個zookeeper節點都需要一個myid檔案來記錄節點在叢集中的id,此檔案只能由一個數字。
echo "1" >> /usr/zookeeper/zk1/data/myid
echo "2" >> /usr/zookeeper/zk2/data/myid
echo "3" >> /usr/zookeeper/zk3/data/myid
# 然後進入 apache-zookeeper-3.7.1-bin的conf資料夾下面,將配置檔案zoo_sample.cfg重名為zoo.cfg。對該檔案進行如下配置
mv zoo_sample.cfg  zoo.cfg
# 加入以下配置 dataDir 儲存資料  dataLogDir 儲存日誌  clientPort 監聽埠
dataDir=/usr/zookeeper/zk1/data 
dataLogDir=/usr/ZooKeeper/zk1/logs
clientPort=2181
server.1=127.0.0.1:8881:7771
server.2=127.0.0.1:8882:7772
server.3=127.0.0.1:8883:7773
#叢集配置中模版為 server.id=host:port:port,id 是上面 myid 檔案中配置的 id;ip 是節點的 ip,第一個 port 是節點之間通訊的埠,第二個 port 用於選舉 leader 節點
# 第一個編輯完,我們用複製指令將這個配置檔案複製到zk2和zk3中。注意要改clientPort dataDir dataLogDir
 /usr/zookeeper/zk1/apache-zookeeper-3.7.1-bin/bin/zkServer.sh start
 /usr/zookeeper/zk2/apache-zookeeper-3.7.1-bin/bin/zkServer.sh start
 /usr/zookeeper/zk3apache-zookeeper-3.7.1-bin/bin/zkServer.sh start
 # 正常啟動會輸出 Starting zookeeper ... STARTED 如果不放心可以用jps指令進行監測

節點的增刪改查

像是Redis 有Redis Cli一樣,Zookeeper也有對應的客戶端我們藉助這個客戶端來實現建立節點操作。

  • 永久節點
#連線zk1
/usr/zookeeper/zk1/apache-zookeeper-3.7.1-bin/bin/zkCli.sh -server 127.0.0.1:2181
# 建立一個節點 dog 是key 123 是value
create /dog 123 
# 獲取目錄中儲存的值
get /dog
# 現在連線zk2 獲取dog節點
/usr/zookeeper/zk2/apache-zookeeper-3.7.1-bin/bin/zkCli.sh -server 127.0.0.1:2181
# 獲取dog目錄中儲存的值 會發現能夠獲取的到
get /dog
  • 臨時節點

    # 連線zk1 建立臨時節點 -e 代表臨時節點
    create -e /dog/cat  123
    # 連線zk2 獲取/dog/cat
    get /dog/cat
    # 在zk1中輸入quit指令,斷掉當前會話
    quit
    # 在zk2就獲取不到了

    建立臨時節點

    zk2能獲取到

zk2能獲取到

zk2就獲取不到了

  • 經典案例基: 基於Znode臨時順序節點+Watcher機制實現公平分散式鎖

​ 原理如下:

公平分散式鎖

請求A首先來到Zookeeper請求建立臨時順序節點,Zookeeper為請求A生成節點,請求A檢查lock目錄下自己的序號是否最小,如果是代表加鎖成功,B監聽節點順序值小於自己的節點的變化,如果A執行則B去獲取鎖,如果有C、D等更多的客戶端監聽,道理是一樣的。

create -s -e /dog/pig  s #在dog下建立臨時順序節點
# 返回值Created /dog/pig0000000001 

寫在最後

其實Zookeeper還有其他功能,如下:

  • 資料的釋出和訂閱
  • 服務註冊與發現
  • 分散式配置中心
  • 命名服務
  • 分散式鎖
  • Master 選舉
  • 負載均衡
  • 分散式佇列

這裡只介紹了基本的概念和應用,希望會對大家學習Zookeeper有所幫助,放英文註釋也是提升自己閱讀英文技術文件的水平。

參考資料

相關文章