Eureka服務端源碼流程梳理


一、簡述

spring cloud三步走,一導包,二依賴,三配置為我們簡化了太多東西,以至於很多東西知其然不知其所以然,了解底層實現之后對於一些問題我們也可以快速的定位問題所在。

spring cloud很多東西都是基於注解實現的,最開始接觸的很迷,怎么一個注解就可以搞定這么多事情,那些配置是怎么加載到spring容器的?

了解springboot的都會知道在jar包里面一般都會都有一個spring.factories的配置文件,里面配置了很多配置類得路徑,這里就是加載相關配置類得入口。

其次就是針對springcloud里面注解,一般來說在某個注解同級目錄里面都會有xxxxxxxAutoConfiguration這樣的配置類,里面會去初始化相關的bean,比如在EnableEurekaServer注解的同級目錄就有EurekaServerAutoConfiguration這個玩意兒,而EurekaServerAutoConfiguration這個玩意兒就是配置在spring.factories里面的

二、、Eureka架構圖及描述

 

 

 

1.服務注冊(register):Eureka Client會通過發送REST請求的方式向Eureka Server注冊自己的服務,提供自身的元數據,比如ip地址、端口、運行狀況指標的url、主頁地址等信息。Eureka Server接收到注冊請求后,就會把這些元數據信息存儲在一個雙層的Map中。
2.服務續約(renew):在服務注冊后,Eureka Client會維護一個心跳來持續通知Eureka Server,說明服務一直處於可用狀態,防止被剔除。Eureka Client在默認的情況下會每隔30秒(eureka.instance.leaseRenewallIntervalInSeconds)發送一次心跳來進行服務續約。
3.服務同步(replicate):Eureka Server之間會互相進行注冊,構建Eureka Server集群,不同Eureka Server之間會進行服務同步,用來保證服務信息的一致性。
4.獲取服務(get registry):服務消費者(Eureka Client)在啟動的時候,會發送一個REST請求給Eureka Server,獲取上面注冊的服務清單,並且緩存在Eureka Client本地,默認緩存30秒(eureka.client.registryFetchIntervalSeconds)。同時,為了性能慮,Eureka Server也會維護一份只讀的服務清單緩存,該緩存每隔30秒更新一次。
5.服務調用:服務消費者在獲取到服務清單后,就可以根據清單中的服務列表信息,查找到其他服務的地址,從而進行遠程調用。Eureka有Region和Zone的概念,一個Region可以包含多個Zone,在進行服務調用時,優先訪問處於同一個Zone中的服務提供者。
6.服務下線(cancel):當Eureka Client需要關閉或重啟時,就不希望在這個時間段內再有請求進來,所以,就需要提前先發送REST請求給Eureka Server,告訴Eureka Server自己要下線了,Eureka Server在收到請求后,就會把該服務狀態置為下線(DOWN),並把該下線事件傳播出去。
7.服務剔除(evict):有時候,服務實例可能會因為網絡故障等原因導致不能提供服務,而此時該實例也沒有發送請求給Eureka Server來進行服務下線,所以,還需要有服務剔除的機制。Eureka Server在啟動的時候會創建一個定時任務,每隔一段時間(默認60秒),從當前服務清單中把超時沒有續約(默認90秒,eureka.instance.leaseExpirationDurationInSeconds)的服務剔除。
8.自我保護:既然Eureka Server會定時剔除超時沒有續約的服務,那就有可能出現一種場景,網絡一段時間內發生了異常,所有的服務都沒能夠進行續約,Eureka Server就把所有的服務都剔除了,這樣顯然不太合理。所以,就有了自我保護機制,當短時間內,統計續約失敗的比例,如果達到一定閾值,則會觸發自我保護的機制,在該機制下,Eureka Server不會剔除任何的微服務,等到正常后,再退出自我保護機制。自我保護開關(eureka.server.enable-self-preservation: false)

三、EurekaServer源碼流程梳理圖

首先推薦一個在線畫圖工具https://www.processon.com,按照流程圖里面的類和方法去和源碼對號入座。

 

 

四、服務端注冊接口和注冊列表獲取接口(2019.05.03補充)

多級緩存設計思想:盡可能保證了內存注冊表數據不會出現頻繁的讀寫沖突問題,進一步保證對Eureka Server的大量請求,都是快速從純內存走,性能極高

1.在拉取注冊表的時候:
    首先從ReadOnlyCacheMap里查緩存的注冊表。
    若沒有,就找ReadWriteCacheMap里緩存的注冊表。
    如果還沒有,就從內存中獲取實際的注冊表數據。
2.在注冊表發生變更的時候:
    會在內存中更新變更的注冊表數據,同時過期掉ReadWriteCacheMap。
    此過程不會影響ReadOnlyCacheMap提供人家查詢注冊表。
    默認每30秒Eureka Server會將ReadWriteCacheMap更新到
    ReadOnlyCacheMap里
    默認每180秒Eureka Server會將ReadWriteCacheMap里是數據失效
   下次有服務拉取注冊表,又會從內存中獲取最新的數據了,同時填充 各級緩存。

 

存在的問題:

1.當我們eureka服務實例有注冊或下線或有實例發生故障,內存注冊表雖然會及時更新數據,但是客戶端不一定能及時感知到,可能會過30秒才能感知到,因為客戶端拉取注冊表實例這里面有一個多級緩存機制


2.服務剔除的不是默認90秒沒心跳的實例,剔除的是180秒沒心跳的實例(eureka的bug導致)

 

/**
     * Renew the lease, use renewal duration if it was specified by the
     * associated {@link T} during registration, otherwise default duration is
     * {@link #DEFAULT_DURATION_IN_SECS}.
     */
    public void renew() {
        lastUpdateTimestamp = System.currentTimeMillis() + duration;

    }

 

加了兩次duration值,com.netflix.eureka.lease.Lease#isExpired(long)

 

 

 /**
     * Checks if the lease of a given {@link com.netflix.appinfo.InstanceInfo} has expired or not.
     *
     * Note that due to renew() doing the 'wrong" thing and setting lastUpdateTimestamp to +duration more than
     * what it should be, the expiry will actually be 2 * duration. This is a minor bug and should only affect
     * instances that ungracefully shutdown. Due to possible wide ranging impact to existing usage, this will
     * not be fixed.
     *
     * @param additionalLeaseMs any additional lease time to add to the lease evaluation in ms.
     */
    public boolean isExpired(long additionalLeaseMs) {
        return (evictionTimestamp > 0 || System.currentTimeMillis() > (lastUpdateTimestamp + duration + additionalLeaseMs));
    }

 

 

 

流程圖:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM