服務註冊中心不可能是單點的,一定會有一個集羣,那麼集羣中的服務註冊信息如何在集羣中保持一致的呢?
首先要明確的是 Eureka 是弱數據一致性的。
下面從2個方面來說明:
- 什麼是弱數據一致性
- Eureka 是如何同步數據的
1. 弱數據一致性
我們知道 ZooKeeper 也可以實現數據中心,ZooKeeper 就是強一致性的。
分佈式系統中有一個重要理論:CAP。
該理論提到了分佈式系統中的3個特性:
- Consistency 數據一致性
分佈式系統中,數據會存在多個副本中,有一些問題會導致寫入數據時,一部分副本成功、一部分副本失敗,造成數據不一致。
滿足一致性就要求對數據的更新操作成功後,多副本的數據必須保持一致。
- Availability 可用性
在任何時候客戶端對集羣進行讀寫操作時,請求能夠正常響應。
- Partition Tolerance 分區容忍性
發生通信故障時,集羣被分割爲多個無法通信的分區時,集羣仍然可用。
CAP 理論指出:這3個特性不可能同時滿足,最多滿足2個。
P 是客觀存在的,不可繞過,那麼就是選擇 C 還是選擇 A。
ZooKeeper 選擇了 C,就是儘可能的保證數據一致性,某些情況下可以犧牲可用性。
Eureka 則選擇了 A,所以 Eureka 具有高可用性,在任何時候,服務消費者都能正常獲取服務列表,但不保證數據的強一致性,消費者可能會拿到過期的服務列表。
Eureka 的設計理念:保留可用及過期的數據總比丟掉可用的數據好。
2. Eureka 的數據同步方式
2.1 複製方式
分佈式系統的數據在多個副本之間的複製方式,主要有:
- 主從複製
就是 Master-Slave 模式,有一個主副本,其他爲從副本,所有寫操作都提交到主副本,再由主副本更新到其他從副本。
寫壓力都集中在主副本上,是系統的瓶頸,從副本可以分擔讀請求。
- 對等複製
就是 Peer to Peer 模式,副本間不分主從,任何副本都可以接收寫操作,然後每個副本間互相進行數據更新。
對等複製模式,任何副本都可以接收寫請求,不存在寫壓力瓶頸,但各個副本間數據同步時可能產生數據衝突。
Eureka 採用的就是 Peer to Peer 模式。
2.2 同步過程
Eureka Server 本身依賴了 Eureka Client,也就是每個 Eureka Server 是作爲其他 Eureka Server 的 Client。
Eureka Server 啓動後,會通過 Eureka Client 請求其他 Eureka Server 節點中的一個節點,獲取註冊的服務信息,然後複製到其他 peer 節點。
Eureka Server 每當自己的信息變更後,例如 Client 向自己發起註冊、續約、註銷請求, 就會把自己的最新信息通知給其他 Eureka Server,保持數據同步。
如果自己的信息變更是另一個Eureka Server同步過來的,這是再同步回去的話就出現數據同步死循環了。
Eureka Server 在執行復制操作的時候,使用 HEADER_REPLICATION
這個 http header 來區分普通應用實例的正常請求,說明這是一個複製請求,這樣其他 peer 節點收到請求時,就不會再對其進行復制操作,從而避免死循環。
還有一個問題,就是數據衝突,比如 server A 向 server B 發起同步請求,如果 A 的數據比 B 的還舊,B 不可能接受 A 的數據,那麼 B 是如何知道 A 的數據是舊的呢?這時 A 又應該怎麼辦呢?
數據的新舊一般是通過版本號來定義的,Eureka 是通過 lastDirtyTimestamp
這個類似版本號的屬性來實現的。
lastDirtyTimestamp
是註冊中心裏面服務實例的一個屬性,表示此服務實例最近一次變更時間。
比如 Eureka Server A 向 Eureka Server B 複製數據,數據衝突有2種情況:
(1)A 的數據比 B 的新,B 返回 404,A 重新把這個應用實例註冊到 B。
(2)A 的數據比 B 的舊,B 返回 409,要求 A 同步 B 的數據。
還有一個重要的機制:hearbeat 心跳,即續約操作,來進行數據的最終修復,因爲節點間的複製可能會出錯,通過心跳就可以發現錯誤,進行彌補。
例如發現某個應用實例數據與某個server不一致,則server放回404,實例重新註冊即可。
3. 小結
- Eureka 是弱數據一致性,選擇了 CAP 中的 AP。
- Eureka 採用 Peer to Peer 模式進行數據複製。
- Eureka 通過 lastDirtyTimestamp 來解決複製衝突。
- Eureka 通過心跳機制實現數據修復。