深入理解SpringCloud源碼探究篇 | Eureka服務端源碼分析

雖然說官方已經發布Eureka不在維護的通知,但是還是需要對我們用過的Eureka進行深入瞭解的,因爲這些玩意都是大同小異的。

下面先利用白話文分析Eureka服務端的實現原理:

eureka服務端:
    EurekaServerAutoConfiguration自動配置類,註冊各種bean,包括PeerAwareInstanceRegistry用於服務註冊(實際就是父類AbstractInstanceRegistry提供的ConcurrentHashMap存放服務註冊列表:registry)、以及jersey。eureka是利用jersey提供接口給客戶端訪問註冊服務和獲取服務列表的,jerseyApplication將註冊DefaultResourceConfig的bean交由spring容器,這裏掃描獲取所有@Path註解的類(這是jersey的註解相當springmvc的@RequestMapping)放入DefaultResourceConfig交由spring容器即可。這樣就啓動了jersey的訪問。

   這裏我們直接從服務註冊接口和服務查詢接口開始對eureka的剖析。ApplicationResource提供註冊接口addInstance,ApplicationsResource提供服務列表獲取getContainers;

    ApplicationResource.addInstance:接收服務註冊請求,將InstanceInfo服務信息調用PeerAwareInstanceRegistry.register將其信息組裝後放入名叫registry(實際就是父類AbstractInstanceRegistry提供的ConcurrentHashMap存放服務註冊列表:registry))的一個ConcurrentHashMap中,這樣就完成了服務註冊操作。
    ApplicationsResource.getContainers:接收服務列表獲取訪問,調用ResponseCacheImpl.getGZIP其實際就是通過readWriteCacheMap(LoadingCache<Key, Value>)中獲取到信息,而這這個readWriteCacheMap信息是在實例化ResponseCacheImpl時進行初始化數據的,初始化是真正調用到的是ResponseCacheImpl.generatePayload進行readWriteCacheMap賦值,而這裏就是從AbstractInstanceRegistry的registry.entrySet()獲取所有服務信息將其進行處理返回。
    服務端通過客戶端發送的心跳進行服務的續約(續約時間固定),當超過續約時間未收到客戶端心跳則會進行剔除操作,當然服務端下線時也會主動觸發請求服務端進行服務剔除,服務續約請求:InstanceResource.renewLease()進行服務時間的刷新;
    主動觸發剔除請求:InstanceResource.cancelLease()調用的是AbstractInstanceRegistry.internalCancel()進行服務刪除;
    定時查看對比各服務的續約時間是否超期,是則發起剔除操作:AbstractInstanceRegistry.evict()查詢服務是否過期,過期的調用AbstractInstanceRegistry.internalCancel()進行服務刪除

eureka服務端核心大致的實現如上面所說, 下面進行源碼的探究:

 

EurekaServerAutoConfiguration自動配置類

我們在demo中使用啓動eureka服務端是啓動類會加上@EnableEurekaServer:

該註解import一個類EurekaServerMarkerConfiguration:

該類實際上什麼都沒有,就是註冊了個空的Marker。

我們回到EurekaServerAutoConfiguration自動配置類中你會發現,這個Marker是啓動自動配置類的條件標識:

接着我們來看看這個自動配置類做了些什麼操作,其他多餘的我就不列了,就繞着前面的白話文裏提到的PeerAwareInstanceRegistry和jersey;

 

服務註冊核心PeerAwareInstanceRegistry類:

 

JerseyApplication:

這裏正如前面所說的掃描出所有@Path和@Provider的類放入DefaultResourceConfig,這裏關於jersey知識我就不這裏描述了,不懂的可以自行百度。

 

這裏我們註冊的比較重要的幾個jersey接口,其中有ApplicationResource,ApplicationsResource,InstanceResource。

ApplicationResource該類提供了服務註冊接口

 

我們先來分析這個服務註冊的過程

首先從接口中我們拿到客戶端提交過來的信息InstanceInfo,該接口其他的各種細節操作我們不需要關注他,拿到info後調用

registry.register(info, "true".equals(isReplication));

也就是調用AbstractInstanceRegistry.register:

 到這裏我們可以看到其實際上就是操作一個叫做registry的ConcurrentHashMap【ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>> 】,具體存放信息結構如下:

{
    "客戶端服務": { // 服務名
        "實例的唯一ID": { // 實例標識符
            "lease": { // 持有實例信息
                "instanceInfo": { // 實例信息
                    "appName": "客戶端服務",
                    "instanceId": "實例的唯一ID",
                    "ipAddr": "IP地址",
                    "port": "調用端口"
                }
            }
        }
    }
}

服務的註冊大概就是這樣子,接着就是服務列表的獲取接口 

ApplicationsResource,提供了所有註冊過的服務列表獲取:

其中重點我們可以看下

 通過調用ResponseCacheImpl.getGZIP來獲取

而這個又接着getValue:

實際上這個值得獲取來自於readWriteCacheMap,然而這個readWriteCacheMap的數據又是從哪而來的呢?

ResponseCacheImpl在被構造時會進行readWriteCacheMap的數據初始化操作:

這裏調用generatePayload:

前面我們傳入的得是ALL_APPS,我們來看看這塊數據的獲取,調用的是AbstractInstanceRegistry.getApplicationsFromMultipleRegions最終獲取的部分核心內容如下:

這裏的registry不正是我們前面註冊時存放進去的服務信息嘛,然後接着獲取所有進行遍歷構造出Applications對象然後進行返回。也就是說前面readWriteCacheMap獲取到的就是Applications信息。到這裏服務的獲取我們也就明白了。

接着就是InstanceResource,該接口提供的是服務的續約請求已經服務的剔除請求:

服務續約請求接口:renewLease

 這裏通過服務名和id最終調用的是AbstractInstanceRegistry.renew:

從服務列表registry裏面獲取對應lease,然後調用對應的renew()方法進行時間的更新:

這樣就完成了服務的續約操作,也就是將服務的更新時間延長一定時間。

接着就是進行服務的剔除接口操作

通過服務名及i最終調用的是AbstractInstanceRegistry.cancal :

接着調用internalCancel:

獲取到對應的instanceInfo然後將其從registry進行remove掉,然後獲取的lease調用cancel()給了個過期時間:

以上是客戶端主動請求剔除操作,還有一個專門的定時任務進行服務的輪詢對比過期時間的剔除操作,同樣的邏輯,這裏就不在贅述了

以上就是本章eureka服務端源碼分析的所有內容,如有什麼不對的地方望指出。感謝你的收看,下章將進行eureka客戶端源碼的探究,如有興趣記得關注哦。

 

 

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