二、Spring Cloud組件 - Eureka

Eureka是什麼?

Eureka是Netflix的子模塊之一,也是一個核心的模塊,eureka裏有2個組件,一個是EurekaServer(一個獨立的項

目) 這個是用於定位服務以實現中間層服務器的負載平衡和故障轉移,另一個便是EurekaClient(我們的微服務)

它是用於與Server交互的,可以使得交互變得非常簡單:只需要通過服務標識符即可拿到服務。

與Spring-cloud的關係

Spring Cloud 封裝了 Netflix 公司開發的 Eureka 模塊來實現服務註冊和發現(可以對比Zookeeper)。

Eureka 採用了 C-S 的設計架構。Eureka Server 作爲服務註冊功能的服務器,它是服務註冊中心。

而系統中的其他微服務,使用 Eureka 的客戶端連接到 Eureka Server並維持心跳連接。這樣系統的維護人員就可

以通過 Eureka Server 來監控系統中各個微服務是否正常運行。SpringCloud 的一些其他模塊(比如Zuul)就可以

通過 Eureka Server 來發現系統中的其他微服務,並執行相關的邏輯。

角色關係圖在這裏插入圖片描述

Eureka結構圖

在這裏插入圖片描述

上圖是官網給的基於集羣部署的 Eureka 架構圖,先看一下圖上各個部件的表示含義以及它們之間的交互:

  • Eureka Server:Eureka 服務端,多個 Eureka Server 可構成集羣,集羣中各節點完全對等。
  • Eureka Client:Eureka 客戶端,業務服務依賴它實現服務註冊和服務發現功能。
  • Application Service:服務提供者,依賴 Eureka Client 實現服務註冊功能。
  • Application Client:服務消費者,依賴 Eureka Client 實現服務發現功能。
  • Register:Eureka Client 啓動時會發起 Register 請求向 Eureka Server 註冊自己。
  • Renew:Eureka Client 會週期性的向 Eureka Server 發送心跳來續約,默認30s。
  • Cancel:Eureka Client 關閉時會發送 Cancel 下線請求。
  • Get:Eureka Client 會週期性的發送 Get 請求,從 Eureka Server 獲取註冊表信息,默認30s。
  • Make Remote Call:服務消費者通過 Make Remote Call 訪問服務提供者。
  • Replicate:Eureka Server 之間通過 Replicate 實現數據同步。當 Eureka Client 有請求(Heartbeat, Register, Cancel, StatusUpdate, DeleteStatusOverride)到某一個 Eureka Server 節點,該節點完成自身對應的操作後,會通過 Replicate 將本次請求同步到其他節點。

注意事項

**【注】**spring-cloud-starter-eureka-server依賴與spring-cloud-starter-netflix-eureka-server的區別

在這裏插入圖片描述

springcloud更新換代比較快,可能1.5可以使用,到了2.0就不用了。所以做項目或者練習時要看清自己使用的版

本。1.5版本使用spring-cloud-starter-eureka-server還是沒問題的。2.0以上建議使用 spring-cloud-starter-

netflix-eureka-server。

官網說明:https://spring.io/projects/spring-cloud-netflix

在這裏插入圖片描述

代碼實戰

詳細請查詢lx-spring-cloud下eureka3000模塊

源碼地址: https://github.com/lxwjq/lx-spring-cloud

Eureka可視化界面詳解

在這裏插入圖片描述

Home

【System Status】
Environment : 環境,默認爲test, 該參數在實際使用過程中,可以不用更改
Data center : 數據中心,使用的是默認的是 “MyOwn”
Current time:當前的系統時間
Uptime : 已經運行了多少時間
Lease expiration enabled :是否啓用租約過期 , 自我保護機制關閉時,該值默認是true, 自我保護機制開啓之後爲false。
Renews threshold : 每分鐘最少續約數
Renews (last min) : 最後一分鐘的續約數量(不含當前,1分鐘更新一次)

【DS Replicas】
這裏表示這個地址是這個Eureka Server相鄰節點,互爲一個集羣

【Instances currently registered with Eureka】
表示各個微服務註冊到這個服務上的實例信息

【General Info】
total-avail-memory : 總共可用的內存
environment : 環境名稱,默認test
num-of-cpus : CPU的個數
current-memory-usage : 當前已經使用內存的百分比
server-uptime : 服務啓動時間
registered-replicas : 相鄰集羣複製節點
unavailable-replicas :不可用的集羣複製節點,如何確定不可用? 主要是server1 向 server2和server3 發送接口查詢自身的註冊信息,
如果查詢不到,則默認爲不可用 , 也就是說如果Eureka Server自身不作爲客戶端註冊到上面去,則相鄰節點都會顯示爲不可用。
available-replicas :可用的相鄰集羣複製節點

Last 1000 since startup

  • Last 1000 cancelled leases(最後1000個取消的租約)
  • Last 1000 newly registered leases(最後1000個新註冊的租約)

配置文件說明

Eureka自我保護機制

eureka:
  server:
    enable-self-preservation:   #自我保護機制配置

默認情況下,如果Eureka Server在一定時間內(默認90秒)沒有接收到某個微服務實例的心跳,Eureka Server

將會移除該實例。但是當網絡分區故障發生時,微服務與Eureka Server之間無法正常通信,而微服務本身是正常

運行的,此時不應該移除這個微服務,所以引入了自我保護機制。

  • 自我保護模式正是一種針對網絡異常波動的安全保護措施,使用自我保護模式能使Eureka集羣更加的健壯、穩定的運行。

  • 自我保護機制的工作機制是如果在15分鐘內超過85%的客戶端節點都沒有正常的心跳,那麼Eureka就認爲客戶端與註冊中心出現了網絡故障,Eureka Server自動進入自我保護機制

**【注意】**該保護機制的目的是避免網絡連接故障,在發生網絡故障時,微服務和註冊中心之間無法正常通

信,但服務本身是健康的,不應該註銷該服務。 如果eureka因網絡故障而把微服務誤刪了,那即使網絡恢復了,

該微服務也不會重新註冊到eureka server了,因爲只有在微服務啓動的時候纔會發起註冊請求,後面只會發送心

跳和服務列表請求,這樣的話,該實例雖然是運行着,但永遠不會被其它服務所感知。 所以,eureka server在短

時間內丟失過多的客戶端心跳時,會進入自我保護模式,該模式下,eureka會保護註冊表中的信息,不在註銷任

何微服務,當網絡故障恢復後,eureka會自動退出保護模式。自我保護模式可以讓集羣更加健壯。

但是我們在開發測試階段,需要頻繁地重啓發布,如果觸發了保護機制,則舊的服務實例沒有被刪除,這時請求有

可能跑到舊的實例中,而該實例已經關閉了,這就導致請求錯誤,影響開發測試。所以,在開發測試階段,我們可

以把自我保護模式關閉,只需在eureka server配置文件中加上如下配置即可:

eureka:
  server:
    enable-self-preservation: false  #關閉自我保護機制

但在生產環境,不會頻繁重啓,所以,一定要把自我保護機制打開,否則網絡一旦終端,就無法恢復。

Eureka緩存機制

註冊表的存儲結構 AbstractInstanceRegistry.java

private final ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> registry = new ConcurrentHashMap();

@Override
public synchronized void initializedResponseCache() {
    if (responseCache == null) {
        responseCache = new ResponseCacheImpl(serverConfig, serverCodecs, this);
    }
}

先來看一下註冊表的存儲結構,上圖 ConcurrentHashMap<String, Map<String, Lease>> register 就是註冊表。

ConcurrentHashMap 的 key 存儲的是服務名稱,value 的這個 Map 存儲的是該服務對應的多個實例信息,Map

的 key 存儲的是服務實例的id,value 的 Lease 就是實例信息,InstanceInfo 就代表了服務實例的具體信息,比如

機器的ip地址、hostname 以及端口號,Lease 可以理解爲 InstanceInfo 的包裝類,維護了服務實例的一些動態

數據,比如最近的心跳時間。另外,從源碼中可以看到,register 是完全基於內存的,服務的註冊、下線、故障,

全部會在內存裏維護和更新這個註冊表。

緩存配置類 ResponseCacheImpl.java

private final LoadingCache<Key, Value> readWriteCacheMap;


public void invalidate(Key... keys) {
    for (Key key : keys) {
        logger.debug("Invalidating the response cache key : {} {} {} {}, {}",
                key.getEntityType(), key.getName(), key.getVersion(), key.getType(), key.getEurekaAccept());

        readWriteCacheMap.invalidate(key);
        Collection<Key> keysWithRegions = regionSpecificKeys.get(key);
        if (null != keysWithRegions && !keysWithRegions.isEmpty()) {
            for (Key keysWithRegion : keysWithRegions) {
                logger.debug("Invalidating the response cache key : {} {} {} {} {}",
                        key.getEntityType(), key.getName(), key.getVersion(), key.getType(), key.getEurekaAccept());
                readWriteCacheMap.invalidate(keysWithRegion);
            }
        }
    }
}

在這裏插入圖片描述

Eureka Server存在三個變量:(registry、readWriteCacheMap、readOnlyCacheMap)保存服務註冊信息,默

認情況下定時任務每30s將readWriteCacheMap同步至readOnlyCacheMap,每60s清理超過90s未續約的節點,

Eureka Client每30s從readOnlyCacheMap更新服務註冊信息,而UI則從registry更新服務註冊信息。

  • 註冊:
    • Eureka Client 發起 Register 請求。
    • Eureka Server 將 Eureka Client 信息添加到註冊表,同時使 ReadWriteCacheMap 緩存失效。
    • 一段時間後(默認30s),Eureka Server 的後臺線程發現 ReadWriteCacheMap 被清空了,就會清空 ReadOnlyCacheMap 緩存。
  • 獲取註冊表:
    • Eureka Client 發起Get請求。
    • 首先,從 ReadOnlyCacheMap 緩存查詢,有就返回。
    • 如果沒有,從 ReadWriteCacheMap 緩存查詢,有就返回。
    • 如果還沒有,就查詢內存中的註冊表,同時將結果填充到 ReadWriteCacheMap 緩存和 ReadOnlyCacheMap 緩存。

這就是 Eureka Server 端的緩存機制,通過 ReadWriteCacheMap 緩存和 ReadOnlyCacheMap 緩存減少了註冊表的讀寫衝突,起到了類似於讀寫分離的效果,進一步保證了 Eureka 的性能。

同時 Eureka Client 端也緩存了一份註冊表信息,週期性的從 Eureka Server 拉取最新的數據。

三級緩存

緩存 類型 說明
registry ConcurrentHashMap 實時更新,類AbstractInstanceRegistry成員變量,UI端請求的是這裏的服務註冊信息
readWriteCacheMap Guava Cache/LoadingCache 實時更新,類ResponseCacheImpl成員變量,緩存時間180秒
readOnlyCacheMap ConcurrentHashMap 週期更新,類ResponseCacheImpl成員變量,默認每30s從readWriteCacheMap更新,Eureka client默認從這裏更新服務註冊信息,可配置直接從readWriteCacheMap更新

緩存相關配置

配置 默認 說明
eureka.server.useReadOnlyResponseCache true Client從readOnlyCacheMap更新數據,false則跳過readOnlyCacheMap直接從readWriteCacheMap更新
eureka.server.responsecCacheUpdateIntervalMs 30000 readWriteCacheMap更新至readOnlyCacheMap週期,默認30s
eureka.server.evictionIntervalTimerInMs 60000 清理未續約節點(evict)週期,默認60s
eureka.instance.leaseExpirationDurationInSeconds 90 清理未續約節點超時時間,默認90s

eureka對比Zookeeper

CAP 不在詳細講解

Consistency —一致性
Availability —可用性
Partition tolerance —分區容錯性

一致性與可用性互斥,不能同時實現。

Zookeeper在設計的時候遵循的是CP原則,即一致性,Zookeeper會出現這樣一種情況,當master節點因爲網絡故障與其他節點失去聯繫時剩餘節點會重新進行leader選舉,問題在於,選舉leader的時間太長:30~120s,且選舉期間整個Zookeeper集羣是不可用的,這就導致在選舉期間註冊服務處於癱瘓狀態,在雲部署的環境下,因網絡環境使Zookeeper集羣失去master節點是較大概率發生的事情,雖然服務能夠最終恢復,但是漫長的選舉時間導致長期的服務註冊不可用是不能容忍的。

Eureka在設計的時候遵循的是AP原則,即可用性。Eureka各個節點(服務)是平等的, 沒有主從之分,幾個節點down掉不會影響正常工作,剩餘的節點(服務) 依然可以提供註冊與查詢服務,而Eureka的客戶端在向某個Eureka註冊或發現連接失敗,則會自動切換到其他節點,也就是說,只要有一臺Eureka還在,就能註冊可用(保證可用性), 只不過查詢到的信息不是最新的(不保證強一致),除此之外,Eureka還有自我保護機制,如果在15分鐘內超過85%節點都沒有正常心跳,那麼eureka就認爲客戶端與註冊中心出現了網絡故障,此時會出現一下情況:

1:Eureka 不再從註冊列表中移除因爲長時間沒有收到心跳而過期的服務。

2:Eureka 仍然能夠接收新服務的註冊和查詢請求,但是不會被同步到其它節點上(即保證當前節點可用)

3:當網絡穩定後,當前實例新的註冊信息會被同步到其它節點中

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章