Consul的架構
如下圖所示:
通常情況下, 一個數據中心由client和server組成, 並且需要保證server相對較少, 因爲server越多, server之間達成一致的速度越慢。
一個數據中心的所有agent都參與一個gossip協議。
Consul使用gossip協議來管理集羣中的成員關係, 廣播消息到集羣中。所有的這些都是通過Serf庫實現的, serf使用的gossip協議是SWIM(Scalable Weakly-consistent infection-style process group membership protocol).
client: 即以client模式啓動的consul客戶端, 通常情況下只是轉發請求到server, 並且佔用的資源極少。
server: 即以server模式啓動的consul客戶端。每個數據中心的所有server都是一個Raft peer set中的一員, 他們的職責通常包括選舉出一個leader, 這個leader負責處理所有請求和事務。 作爲一致性協議的一部分,事務會被轉發到peer set中的所有成員。當一個非leader的server接收到一個RPC請求時, 它會轉發請求到當前數據中心的leader。
Consul使用基於Paxos的Raft來提供一致性協議(consensus protocol),即CAP中的C。相比於Paxos, Raft擁有更少的狀態, 並且算法也更容易理解。
Raft中有幾個關鍵的概念:
Log : 在一個Raft系統中, 最基礎的工作單位就是一條log記錄。 因此一致性的問題也就成了log的一致性問題。 Log是有序的, 包含了集羣(cluster)中的所有的變化:添加節點, 添加服務, 增加key-value鍵值對等等。當所有的集羣成員都同意log中的記錄以及順序時, 這個log被認爲是一致的。
FSM: 無限狀態機, 一個無限狀態機就是有限狀態機的集合,並且包含了它們之間轉換的方法。當新的log被應用的時候, FSM被允許在狀態之間進行轉換。擁有相同順序的所有log的應用程序必然最終會到達同一個狀態。
Peer set: 一個peer set即使參與log備份的所有的成員。 從Consul的角度來說, 所有的server節點都參與到本地數據中心的peer set中。
Quorum: 一個quorum是一個peer set中的主要成員, 必須如果peer set大小爲n
,則quorum要求至少(n/2)+1
個成員。如果一個集羣中一個quorum數量的節點失敗, 則這個集羣就無法提供服務, 並且無法提交新的log。
Committed Entry: 當一個entry被持久化到一個quorum數量的節點上時, 這個log記錄被認爲是已提交, 並可以被應用到狀態機。
Leader: 在任何時間, 一個peer set中只有一個節點可以成爲leader, leader負責生成新的日誌記錄, 傳播到follower中, 並且決定何時一個記錄被認爲是已提交。
一個Raft節點總共有三個狀態:follower, candidate或者leader.
所有節點啓動時是follower狀態, 在這個狀態,節點可以接收leader的日誌記錄並且參與Leader選舉投票。當節點在一段時間沒有接收到Leader的日誌記錄時, 節點會自動進入candidate狀態。
在candidate狀態中, 節點要求peer set中的其他成員投票, 如果投票超過一個quorum數量, 則會成爲leader。
Leader必須接收新的日誌記錄並且傳播到其他的follower中。如果請求不接受過期的數據, 則所有的查詢請求必須由leader來響應。
Raft提供了一個機制, 可以快照保存當前的狀態並且壓縮日誌 , 這樣可以把保存的狀態之前的所有日誌移除到, 以節省空間, 這個是Raft自動完成的。Consul使用MemDB保存集羣的狀態, 而MemDB的一個優點就是可以在快照保存狀態機的狀態時依然接收新的事務。
Raft In Consul
剛開始時, 一個Consul server可以以"bootstrap"模式啓動, 這個模式可以允許server自選爲leader。 一旦leader確定, 其他的server就會加入到這個peer set中。
由於所有的節點都知道當前的Leader, 當RPC請求到達非leader server時,請求被轉發leader。
如果這個請求時查詢類型, 則leader基於狀態機當前的狀態生成結果;
如果這個請求時事務類型(transaction type), 意味着是更改狀態, 則leader生成一個新的log記錄, 並且通過Raft應用這條記錄。
一致性模式
所有的修改請求都會經過Raft形成日誌記錄, 但是讀請求卻有更多的選項。Consul支持3種讀一致性模式:
default: Raft通過leader租賃的方法, 保證在一個時間窗口內, leader的角色是不變的。
consistent: 強一致性模式, 每次都要向一個quorum數量的server確定它仍然是leader。
stale: 允許任何server響應讀請求。
Session
Consul提供了一個session的機制來構建分佈式鎖。 Session像是一個node, health checks以及key/value數據之間的綁定層, 提供精細的鎖。
在以下情況下, session會失效:
-
節點註銷
-
-
health check未通過
-
session被顯示銷燬
-
TTL過期
當session過期時, session上的鎖可能有兩種情況: 一是release
, 這是默認行爲, 二是delete
。Session必須在使用前創建, 然後引用它的ID。
Consul中的KV 接口被擴展成支持aquire
和release
操作。aquire
和release
均通過check-and-set的方式執行。獲取鎖成功, 則key的LockIndex
增加, 當一個鎖釋放的時候,key對應的ModifyIndex
增加。
Consul的安全模型
Consul依賴於一個輕量級的gossip以及一個RPC系統提供各種各樣的系統(RPC系統在0.8版本中被移除, 官方建議使用HTTP接口)。它們都有各自的安全機制。例如gossip協議使用對稱密鑰, 共享密鑰及密碼系統, RPC系統使用端對端加密來完成客戶端驗證。
這些安全機制都不是默認開啓的, 需要自己啓用。
推薦的安全機制:
ACL+默認拒絕:Consul配置成啓用ACL並且使用白名單方式, 默認拒絕。所有的請求必須有顯示的匿名token, 或者驗證的ACL token。
開啓加密: 開啓TCP和UDP加密, 從而使用agent之間的數據連接都是加密的。