一、分散式架構 1、分散式特點 分佈性 對等性。分散式系統中的所有電腦節點都是對等的 併發性。多個節點併發的操作一些共用的資源 缺乏全局時鐘。節點之間通過消息傳遞進行通信和協調,因為缺乏全局時鐘,很難定義兩個事件誰先誰後 故障總是會發生。系統設計時,需要考慮到任何異常情況 2、分散式環境的各種問題 ...
一、分散式架構
1、分散式特點
- 分佈性
- 對等性。分散式系統中的所有電腦節點都是對等的
- 併發性。多個節點併發的操作一些共用的資源
- 缺乏全局時鐘。節點之間通過消息傳遞進行通信和協調,因為缺乏全局時鐘,很難定義兩個事件誰先誰後
- 故障總是會發生。系統設計時,需要考慮到任何異常情況
2、分散式環境的各種問題
- 通信異常。分散式系統中的某些節點之間無法正常通信
- 網路分區。這有部分節點可以正常通信,有些無法正常通信。這種現象稱為網路分區,也稱為“腦裂”
- 三態。節點之間的一次通信存在三種狀態:成功、失敗、超時
- 節點故障。節點機器宕機、失去回應
3、傳統事務的ACID理論。
- 原子性(Atomicity)。事務內的所有操作要麼全部成功,要麼全部失敗
- 一致性(Consistency)。事務的執行不能破壞資料庫的一致性。如果事務執行一半停了,一部分的修改寫入的資料庫。這時候,資料庫就處於一種不正確的狀態,或者說不一致的狀態
- 隔離性(Isolation)。多個事務併發執行,彼此不會受影響。事務的隔離級別:讀未提交(可能發生臟讀、重覆讀、幻象讀)、讀已提交(肯能發生重覆讀、幻象讀)、可重覆讀(可能發生幻象讀)、串列化。隔離級別越高,對併發的性能影響越大,越能保證資料庫的一致性。
- 持久性(Durablility)。一旦事務成功提交,它對於數據的修改就被永久保存下來
4、分散式事務的CAP理論和BASE理論
- CAP理論。一致性(Consistency)、可用性(Availability)、分區容錯性(Partition tolerance),在分散式系統中,最多只能滿足其中的兩項。
- BASE理論。基本可用(Basically Available)、軟狀態(Soft state)、最終一致性(Eventually consistent)。基本可用指系統出現故障時,允許損失部分可用性,包括響應時間的損失和功能上的系統降級;軟狀態指允許節點間的通訊出現中間狀態;最終一致指系統的所有的數據副本,在一定時間的同步後,最終能夠達到一致的狀態
二、一致性協議
1、2PC。二階段提交協議
階段一,執行事務
- 事務詢問。協調者向所有參與者發送事務內容,等待參與者回應
- 執行事務。參與者執行事務,記錄Undo和Redo日誌
- 反饋事務詢問響應,參與者返回給協調者Yes或No響應。全部返回Yes,進入提交事務階段;存在No返回或者超時,進入中斷事務階段
階段二,提交事務
- 發送事務提交請求
- 各個參與者提交事務
- 參與者反饋事務提交結果
- 如果參與者全部返回Yes,完成事務;存在返回No,進入中斷事務階段
中斷事務階段
- 發送回滾請求
- 事務回滾
- 反饋事務回滾結果
- 完成中斷事務
2PC的缺點
- 同步阻塞。各個參與者在等待其他參與者響應的同時,無法進行任何操作,處於阻塞狀態
- 單點問題。過度依賴協調者,一旦協調者出現問題,系統將無法正常運轉
- 數據不一致。同上一條,一旦協調者出現問題,就可能出現各個參與者數據不一致的問題
- 太過保守。一旦參與者出現故障,協調者只能通過自己的超時機制發現。
2、3PC。三階段提交協議
階段一,CanCommit,事務詢問
- 事務詢問,詢問各個參與者能否完成事務
- 各個參與者返迴響應,全部返回Yes,進入PreCommit階段
階段二,PreCommit,事務預提交
- 發送預提交請求
- 事務預提交。參與者執行事務操作,記錄Undo和Redo日誌
- 參與者返迴響應。全部返回Yes,繼續三階段;返回No,進入中斷事務階段
階段三,DoCommit,真正的事務提交
- 發送提交請求
- 參與者正式執行事務提交操作
- 返回協調者事務執行結果
- 協調者完成事務。如果存在返回No或者返回超時,進入中斷事務階段
中斷事務階段
- 發送回滾請求
- 事務回滾
- 反饋事務回滾結果
- 完成中斷事務
3PC優缺點
- 相較於2PC,3PC最大優點就是降低了參與者的阻塞範圍
- 缺點是,還是避免不了出現數據不一致的情況
3、Paxos演算法
拜占庭將軍問題,拜占庭帝國的不同軍隊處於不同的地理問題,他們之間只能通過通訊員進行通訊,但是通訊員是不可靠的,可能篡改消息
由於加密演算法和校驗演算法的出現,所有實際的分散式系統之間的通訊,不存在數據被篡改的可能。
四、ZooKeeper和ZAB協議介紹
1、初識ZeeKeeper
ZooKeeper可以做什麼
可以基於它實現負載均衡、集群管理、Master選舉、分散式隊列、分散式鎖、命名服務、數據發佈/訂閱等功能
Zookeeper能保證的分散式一致性特性
- 順序一致性。同一個客戶端發起的請求,會嚴格按照發起順序執行
- 原子性。對於一個事務請求,集群中的所有機器的執行情況是一致的
- 可靠性。一旦服務端成功的應用了一個事務,並完成了對客戶端的響應。服務端的狀態會一直保存下來
- 實時性。保證在一段時間內的實時性
- 單一視圖。無論客戶端連接的是哪一個伺服器,看到的服務端的數據模型都是一致的
Zookeeper的設計目標
- 簡單的數據模型。Zookeeper將去數據存儲在記憶體中,採用樹形結構存儲,樹由ZNode節點構成
- 可以構建集群。只有集群中超過一半機器能夠正常運作,整個集群就可以正常對外提供服務。
- 順序訪問。每個來自客戶端的請求,都會分配一個全局唯一的遞增編號
- 高性能。全量數據存儲在記憶體中,3台3.4.3的Zookeeper集群,100%讀請求場景的壓測結果是12-13W的QPS
Zookeeper的基本概念
- 集群角色。存在Leader、Follower、Observer三種角色。Leader伺服器提供讀和寫服務,Follower和Observer提供讀服務,但是Observer不參與選舉過程,也不參與寫操作的“過半寫”策略,因此,Observer可以在不影響寫性能的情況下提高讀性能
- 客戶端會話。客戶端通過TCP長連接和服務端相連,第一次建立連接就代表客戶單會話開始了。客戶端能夠通過心跳檢測與伺服器保持有效的會話。Session的SessionTimeout值用來設置會話的超時時間,連接斷開後,只要在超時時間之內重新連接上了集群中的任何一臺伺服器,那麼之前創建的會話仍然有效
- 節點。一方面只集群中的每一臺機器,稱為機器節點;另一方面指數據模型中的數據單元,稱為數據節點Znode。Znode又分為持久節點和臨時節點,臨時節點的生命周期和會話綁定,一旦客戶端會話失效,那麼這個客戶端創建的所有臨時節點都會被移除。
- 版本。每個Znode,會維護一個叫做Stat的數據結構,記錄了Znode的三個版本:version(當期版本)、cversion(當前Znode子節點的版本)、aversion(當前Znode的ACL版本)。
- Watcher。事件監聽器,允許用戶在一些節點上註冊一些watcher。特性事件觸發的時候,伺服器會將事件通知到感興趣的客戶端上去。
- ACL。許可權控制策略(Access Control Lists)。定義了五種許可權:Create(創建子節點)、Delete(刪除子節點)、read(讀取節點數據和子節點列表)、write(更新節點數據)、admin(設置節點ACL的許可權)
2、ZAB協議(Zookeeper Atomic Broadcast,原子消息廣播協議)
所有事務請求都由Leader伺服器來處理分發,如果集群中的其他伺服器收到了來自客戶端的請求,這些非Leader伺服器會首先將這個事務請求轉發給Leader伺服器,Leader負責將請求封裝成Proposal(提議)分發給集群中所有Follower,一旦收到超過半數的正確反饋,Leader就會再次向所有的Follower分發Commit消息,要求他們將前一個Prosocal提交
兩種基本模式:崩潰恢復模式和消息廣播模式
- 消息廣播模式。類似於二階段提交,去掉了中斷邏輯,當Leader伺服器收到了超過半數的Follower的ACK響應後,就會廣播一個Commit消息給所有的Follower進行事務提交。
- 崩潰恢復。一旦Leader伺服器出現崩潰,或者由於網路原因失去了一半Follower伺服器的聯繫,就會進入崩潰恢復模式。
- 崩潰恢復需要確保已經被Leader提交的Proposal也能被所有Follower提交
- 確保丟棄只在Leader伺服器上提出的事務。(此處的提出指的是二階段第一階段)。重新選舉出來的Leader擁有集群中所有伺服器最高編號的事務Proposal
- 正常情況的數據同步:Leader伺服器為每一個Follower伺服器準備一個隊列,將那些沒有被Follower伺服器同步的事務以Proposal消息的形式逐個發送給Follower,等待所有事務都同步到了Follower併成功應用到了Follower的本地資料庫中後,Leader伺服器就將該Follower伺服器加入到真正的可用列表中
- 事務編號ZXID,是一個64位的數字。前32位存儲Leader屆數,後32位記錄本屆Leader處理的消息數。
3、深入ZAB協議
運行分析,每一個進程都有可能處於以下三種狀態之一
- LOOKING:leader選舉階段
- FOLLOWING:Follower伺服器和Leader伺服器保持同步狀態
- LEADING:Leader伺服器作為主進程領導狀態
五、使用Zookeeper
1、服務端部署與運行
- 初次使用,需要把/conf目錄下的zoo_sample.cfg文件重命名為zoo.cfg。配置如下:
- server.1=IP1:2888:3888,每一行這樣的配置代表一個集群中的一個機器,server.1中的1代表ServerID,同時在每台機器上需要在數據目錄(dataDir指定的目錄)下創建一個myid文件,文件內容就是ServerID,id範圍是1~255
- 集群中每個機器的zoo.cfg文件都應該是相同的,最好使用git或者svn把配置管理起來
- 啟動服務。/bin/zhServer.sh start
- 停止服務。/bin/zkServer.sh stop
2、客戶端腳本
- 啟動。/bin/zkCli.sh -server ip:port(不加server參數,預設連接本機)
- 創建節點。create 【-s】【-e】path data acl。acl用來進行許可權控制
- 讀取節點下子節點。ls path。例如:ls / 查看根節點下的所有子節點
- 讀取節點數據。get path
- 更新節點數據。set path data 【version】
- 刪除節點。delete path 【version】。無法刪除一個包含子節點的節點
3、開源客戶端Curator的使用
直接看我的github代碼:https://github.com/leon66666/zookeeper-client
六、Zookeeper的典型應用場景
1、典型應用場景及實現
(1)數據發佈和訂閱
分為推(push)模式和拉(pull)模式,push模式服務端主動把數據更新推送給所有訂閱的客戶端,而拉模式是由客戶端定時輪詢拉取的方式來獲取最新數據
應用場景:分散式系統統一配置,例如機器列表信息、運行時的開關配置、資料庫配置信息等,這些全局配置交給Zookeeper統一管理
這些配置具有以下特點:
- 數據量通常比較小
- 數據內容在運行時動態變化
- 集群中各機器共用,配置一致
(2)負載均衡
DDNS,動態DNS解析。區域網內部一般採用host綁定的方式來進行ip和功能變數名稱的映射。一旦機器規模變大,這種做法就會相當的不方便。
通過Zookeeper實現,每個應用都可以創建一個屬於自己的數據節點作為功能變數名稱配置的根節點,在這個節點上,每個應用都可以將自己的功能變數名稱配置上去。通過註冊Watcher實現功能變數名稱變更通知功能。
上圖為整體的DDNS系統架構。
- Register集群負責功能變數名稱的動態註冊。每個服務者啟動的時候,都會把自己的功能變數名稱信息註冊到Register集群中去。
- Dispatcher集群負責功能變數名稱的解析。服務消費者在使用功能變數名稱的時候,會向Dispatcher集群發出請求,獲取相應的IP:PORT信息。
- Scanner集群負責檢測及維護服務狀態(探測服務可用性、屏蔽異常服務節點)。(一種是心跳檢測,需要客戶端和服務端建立起tcp長連接。另一種是服務端主動進行狀態彙報,一旦超過5秒沒有收到彙報,就認為該IP地址不可用,進行功能變數名稱清理)
- SDK,提供各個語言的系統接入
- Monitor負責收集集群信息以及對DDNS自身的監控
- Controller是一個後臺管理,負責授權管理、流量控制、服務配置和手動屏蔽服務等功能。
(3)命名服務
即分散式環境下,生成全局唯一ID的方法。大家一般會聯想到UUID,是通用唯一識別碼的簡稱。主流ORM框架HIbernate就有對UUID的直接支持。
但是,UUID有如下缺點:
- 長度過長,需要更多的存儲空間
- 含義不明,根據字元串開發人員從字面上根本看不出他的含義
利用Zookeeper來實現這類全局唯一ID的生成。當客戶端創建一個順序子節點的時候,zookeeper會自動以尾碼的形式在其子節點上添加一個序號,利用了zookeeper順序節點的特性
(4)分散式協調/通知
Zookeeper實現分散式協調通知,通常的做法是不同的客戶端都對Zookeeper上同一個數據節點進行Watcher註冊。監聽節點數據的變化。
(5)通用的分散式系統機器間通信方法
分佈西系統機器間通信包括:心跳檢測、工作進度報告、系統調度
- 心跳檢測。不同機器之間需要檢測到彼此是否正常運行。傳統方法通過機器之間能否互相ping通來判斷;更複雜的通過機器之間建立起Tcp長連接,通過tcp固有的心跳檢測機制來實現上層機器的心跳檢測;基於Zookeeper的臨時節點特性也可以實現心跳檢測,不同的機器在指定節點下創建臨時節點,不同機器可以通過判斷臨時節點是否存在來判斷客戶端機器是否存活。減少了系統耦合
- 工作進度報告。每個客戶端創建臨時子節點,各個任務機器會實時的將自己的執行進度存儲到對應的子節點上,也可以判斷子節點是否存在判斷機器是否存活
- 系統調度。一個分散式系統由控制台和客戶端組成。後臺管理人員在控制台做一些操作(實際上就是修改Zookeeper上某些節點的數據),Zookeeper以事件通知的形式發送給對應的訂閱客戶端
(6)集群管理
集群管理需求點
- 知道集群中工作的機器數量
- 對集群中每台機器的運行狀態進行收集
- 對集群中的機器進行上下線操作
傳統的基於agent的管理方式,集群中每台機器部署一個agent,負責本機器的監控和向中心系統彙報
- 大規模升級困難
- 統一的agent無法滿足多樣的需求。無法深入應用內部,對一些業務狀態進行監控
- 編程語言多樣性。不同機器需要提供不同語言的agent
利用zookeeper監控集群
- 客戶端可以對zookeeper節點進行監聽,節點變更會受到通知
- 在zookeeper上創建臨時節點,一旦會話失效,改臨時節點會被自動刪除
- 監控系統在/clusterServers節點上註冊一個Watcher監聽,添加機器會在監聽節點下創建臨時子節點。
zookeeper監控應用:分散式日誌收集系統
- 註冊收集器機器。以/logs/controller作為收集器的根節點,每個收集器啟動的時候都會在收集器節點下創建自己的節點
- 任務分發。收集系統把日誌源機器按照一定策略分配給註冊的收集器機器,將機器列表寫入到對應的收集器節點上
- 狀態彙報。收集器節點下麵創建狀態子節點,每個註冊的收集器機器定時向該節點寫入自己的狀態信息和日誌收集進度信息(可以看做是一種心跳檢測),根據更新時間來判斷是否存活
- 動態分配。檢測到收集器的減少或者增加之後,需要進行重新分配。通常有兩種做法:全局分配(影響面大);局部動態分配(低負載優先分配)
- 節點類型。收集器節點,需使用持久節點,需要保存該節點上的日誌源機器列表
- 收集器節點監聽。放棄監聽設置,採用定期輪詢,節省網卡流量,但是具有一些延時,考慮到日誌收集需求,延時是可以接受的
(7)Master選舉
在集群的所有機器中選舉出一臺機器作為master
- 可以通過資料庫的主鍵唯一特性來實現。但是當選舉出的master掛了之後,資料庫無法通知我們這個事件
- 利用zookeeper的強一致性,客戶端無法創建一個已經存在的節點。其他沒有成功創建這個節點的客戶端會在這個節點上註冊一個子節點變更的watcher,一旦發現當前的master掛了,其餘客戶端會重新進行選舉
(8)分散式鎖
最常見的是用資料庫實現。例如行鎖,表鎖,事務處理,樂觀鎖等等。但是往往分散式系統的性能瓶頸都集中在資料庫的操作上。
- 排它鎖。選擇一個節點作為鎖節點,客戶端加鎖的時候會在鎖節點先創建臨時子節點,利用zookeeper特性,只有一個客戶端能夠創建成功,其餘客戶端註冊鎖節點的子節點變更的Watcher監聽,在持有鎖的客戶端主動刪除臨時節點或者由於宕機導致會話超時導致臨時節點被移除,都表示鎖被釋放了。其他監聽的客戶端會再次發起分散式鎖獲取
- 共用鎖。在鎖節點下創建臨時順序節點。讀節點為R+序號,寫節點為W+序號。創建完節點後,獲取所有子節點,對鎖節點註冊子節點變更的watcher監聽,確定自己的序號在所有子節點中的位置。對於讀請求,沒有比自己序號小的寫節點,就表示獲得了共用鎖,執行讀取邏輯。對於寫請求,如果自己不是序號最小的子節點,就需要進入等待。接收到watcher通知後,重覆獲取鎖。
- 共用鎖羊群效應。大量的watcher通知和子節點列表獲取,兩個操作重覆運行。集群規模比較大的情況下,會對zookeeper伺服器造成巨大的性能影響和網路衝擊
- 改進後的共用鎖。讀請求,監聽比自己小的寫節點。寫請求,監聽比自己小的最後一個節點。
- 具體選用哪種實現的共用鎖,視集群規模而定
(9)分散式隊列