Eureka 系列(02)Eureka 一致性協議
Eureka 是由 Netflix 基於 AP 模型的服務發現中間件,包括服務發現服務器和客戶端的。相關文檔推薦:一是 Spring Cloud Eureka 官網,二是 Eureka源碼解析。
本系列源碼分析基於 spring-cloud-starter-netflix-eureka-2.1.1.RELEASE 和 Eureka-1.9.8。
0. Spring Cloud 系列目錄 - Eureka 篇
1. 服務發現方案對比
1.1 技術選型
技術選型 | CAP模型 | 適用規模(建議) | 控制台管理 | 社區活躍度 |
---|---|---|---|---|
Eureka | AP | <30k | 支持 | 低 |
Zookeeper | CP | <20k | 不支持 | 中 |
Consul | AP | <5k | 支持 | 高 |
Nacos | AP/CP | 100k+ | 支持 | 靠大家啦☺ |
注: 以上數據來源於 小馬哥技術周報。
1.2 數據模型
框架 | 集群(框架) | 服務應用 | 服務集群 | 服務實例 | 租約管理 |
---|---|---|---|---|---|
Spring-Cloud | -- | (serviceId) | -- | ServiceInstance | -- |
Nacos | Server | Service | Cluster | Instance | -- |
Eureka | (serviceUrl) | Application(appName) | -- | InstanceInfo(id) | Lease |
不同的框架對應的數據結構不太一致,在此做一些約定:
- 服務器集群 Server:指的是 Eureka Server 本身的集群。用 Server 代替,也可能是 ServerList 之類,總之與 Server 或 Peer 或 Node 相關的都代表框架自身的集群。
- 服務 Service:代表一個應用,可能包含多個服務實例。
Service(服務)
或serviceId
或Application(應用)
或appName
。 - 集群 Cluster:一個 Service 可能包含多個 Cluster,Cluster 包含多個具體的實例。這是 Nacos 中的概念。
- 服務實例 ServiceInstance:代表注冊的一個具體實例。
ServiceInstance(服務實例)
或InstanceInfo(實例id)
或Instance(實例)
。
2. Eureka 一致性協議
Eureka 和 Zookeeper 的最大區別: Eureka 是 AP 模型,Zookeeper 是 CP 模型。在出現腦裂等場景時,Eureka 可用性是每一位,也就是說出現腦裂時,每個分區仍可以獨立提供服務,是去中心化的。更多 Eureka與ZooKeeper 的比較。
那 Eureka 是如何實現最終一致性的呢?
2.1 消息廣播
-
Eureka Server 管理了全部的服務器列表(PeerEurekaNodes)
-
當 Eureka Server 收到客戶端的注冊、下線、心跳請求時,通過 PeerEurekaNode 向其余的服務器進行消息廣播,如果廣播失敗則重試,直到任務過期后取消任務,此時這兩台服務器之間數據會出現短暫的不一致。
注意: 雖然消息廣播失敗,但只要收到客戶端的心跳,仍會向所有的服務器(包括失聯的服務器)廣播心跳任務。
-
如果網絡恢復正常,收到了其它服務器廣播的心跳任務,此時可能有三種情況:
- 一是腦裂很快恢復,一切正常;
- 二是該實例已經自動過期,則重新進行注冊;
- 三是數據沖突,出現不一致的情況,則需要發起同步請求,其實也就是重新注冊一次,同時踢除老的實例。
總之,通過集群之間的消息廣播可以實現數據的最終一致性。
2.1.2 服務注冊
- Spring Cloud Eureka 在應用啟動時,會在 EurekaAutoServiceRegistration 這個類初始化的時候,主動去 Eureka Server 端注冊。
- Eureka 在啟動完成之后會啟動一個 40 秒執行一次的定時任務,該任務會去監測自身的 IP 信息以及自身的配置信息是否發生改變,如果發生改變,則會重新發起注冊。
- 續約返回 404 狀態碼時,會去重新注冊
2.1.3 主動下線
Eureka 會在 spring 容器銷毀的時候執行 shutDown 方法 ,該方法首先會將自身的狀態改為 DOWN,接着發送cancle 命令至 Eureka Server 請求下掉自己的服務。
2.1.4 心跳續約與自動下線
健康檢測,一般都是 TTL(Time To Live) 機制。eg: 客戶端每 5s 發送心跳,服務端 15s 沒收到心跳包,更新實例狀態為不健康, 30s 未收到心跳包,從服務列表中刪除。
Eureka Server 默認每 30s 發送心跳包,90s 未收心跳則刪除。這個清理過期實例的線程,每 60s 執行一次。
2.2 崩潰恢復
2.2.1 重啟
Spring Cloud Eureka 啟動時,在初始化 EurekaServerBootstrap#initEurekaServerContext 時會調用 PeerAwareInstanceRegistryImpl#syncUp 從其它 Eureka 中同步數據。
2.2.2 腦裂
- 發生腦裂后:和 Eureka Server 同區的服務可以正常訪問,而不同區的服務則自動過期。
- 腦裂恢復后:接收其它 Eureka Sever 發送過來的心跳請求,此時有三種情況:一是腦裂很快恢復,一切正常;二是該實例已經自動過期,則重新進行注冊;三是數據沖突,出現不一致的情況,則需要發起同步請求。
3. 可靠性
3.1 高可用客戶端(Client HA)
當有多個 Eureka Server 時,第一台宕機時會從下一台同步數據。注意:只有當第一台宕機時才會同步第二台,否則永遠只會從第一台同步數據。
3.2 自我保護
如果每分鍾的續約數小於閥值時 ,則開啟自我保護機制,Eureka Server 將不會主動清除過期實例。
每天用心記錄一點點。內容也許不重要,但習慣很重要!