eureka原理
客戶端是如何注冊到注冊中心的
?在eureka的client與server通訊過程中祭埂,client需要把自己的信息發(fā)送到server牌芋,那么client具體是通過什么方式發(fā)送的,又發(fā)送了些什么東西呢侣诺。
?通過eureka的啟動日志可以看到這么一段信息,上面記錄了作為client的時候向服務(wù)發(fā)送注冊信息的注冊狀態(tài)裆泳。那么我們可以通過這段信息查找到DiscoveryClient類打上斷點來看下客戶端是如何注冊的弛姜。
?通過斷點我們可以看到該方法的調(diào)用鏈,在這里面我們可以清晰的看到飒货,在最初始還是一段spring的容器的初始化魄衅,然后通過DefaultLifecycleProcessor來初始化實現(xiàn)了SmartLifecycle接口的EurekaServiceRegistry類,在注冊前置操作完畢之后通過通知listener方式初始化一個定時任務(wù)線程池來重復(fù)執(zhí)行DiscoveryClient的register記錄狀態(tài)的變更塘辅。
?我們現(xiàn)在可以根據(jù)下面的方法邏輯來看下client是如何向服務(wù)器發(fā)送注冊信息的晃虫,并且可以知道具體發(fā)送了一些什么東西。
?通過DiscoveryClient中的register方法我們可以清楚的看到客戶端向服務(wù)端發(fā)送的實例信息扣墩,我們可以看一下在運行時的時候客戶端中有些什么信息哲银。
?由上圖我們可以看出發(fā)送的信息主要有服務(wù)的名稱、IP呻惕、實例名稱及端口信息荆责。具體是通過什么方式發(fā)送的,我們可以通過對象的名稱看出來是通過http的方式發(fā)送蟆融。
注冊中心又是如何接收客戶端的注冊請求
?在我們弄清楚客戶端發(fā)送的注冊信息之后草巡,我們可以繼續(xù)看下注冊中心又是如何接收從客戶端發(fā)送過來的
?通過該日志信息我們可以查到AbstractInstanceRegistry類中有個register輸出了這條日志。那么同樣的方式我們通過斷點來查看調(diào)用鏈。
?通過調(diào)用鏈我們可以清晰的看到客戶端發(fā)送注冊信息到注冊中心山憨,在ApplicationResource#addInstance
對發(fā)送過來信息必要參數(shù)進(jìn)行驗證之后查乒,最終調(diào)用到AbstractInstanceRegistry#register中進(jìn)行信息注冊。該請求接收的方式主要是通過NIO的方式來接收郁竟。
注冊中心是如何存儲注冊信息的
?在我們接收到注冊信息之后我們需要對注冊信息進(jìn)行存儲玛迄,在注冊中心中是通過一個ConcurrentHashMap來存儲的。在第一次注冊的時候會判斷map是否存在如果不存在的話則會創(chuàng)建一個key為String棚亩、value為Lease的ConcurrentHashMap集合對象蓖议,并將注冊信息存儲到該Map中,在之后的注冊信息中則刷新該對象中的信息讥蟆。具體操作邏輯可看下圖:
注冊中心的高可用機(jī)制
?在微服務(wù)體系中勒虾,注冊中心是一個非常重要的服務(wù),如果注冊中心宕機(jī)了瘸彤,那么就會造成服務(wù)之間的調(diào)用無法拿到當(dāng)時時間點有效的服務(wù)器地址修然,這樣就會造成我們各個服務(wù)的調(diào)用失敗,為了保證注冊中心的高可用质况,eureka的注冊機(jī)制中提供了注冊中心的相互注冊愕宋。在這種情況下如果有一臺eureka宕機(jī)了,我們可以通過控臺來看觀察eureka的狀態(tài)结榄,及時通知相關(guān)人員來修復(fù)中贝。
?那么具體在eureka中如何實現(xiàn)高可用呢,我們只需要在server端的配置上加上其他server端的注冊地址臼朗,將該服務(wù)器的信息發(fā)送到其他server端邻寿,這樣eureka就形成了一個集群。
?既然我們已經(jīng)知道是通過這條配置來形成集群的那么我們可以在日志中查找一下依溯,是否有類似的信息老厌。通過下圖的日志打印,我們可以找到有這么一個方法PeerEurekaNodes#start打印出了節(jié)點信息黎炉,那么我們同樣通過斷點的方式來查看一下調(diào)用鏈及運行邏輯枝秤。
?通過調(diào)用鏈我們我們查找到這樣的一段邏輯,從字面上的意思是初始化eureka節(jié)點慷嗜。在eureka的啟動方法中我們可以看到他啟動了一個單線程定時任務(wù)來做eureka集群節(jié)點更新淀弹,至于任務(wù)執(zhí)行使用的參數(shù)信息這個在后面講配置的時候會說到。
?通過源碼的追蹤我們知道在第一次更新節(jié)點信息的時候創(chuàng)建用于server通訊的JerseyReplicationClient
庆械。在創(chuàng)建的時候會根據(jù)配置的屬性信息選擇是否需要使用ssl薇溃,并且將這個通訊客戶端封裝成一個PeerEurekaNode對象用來指代eureka的遠(yuǎn)程server服務(wù)。
缭乘。
?在PeerEurekaNode創(chuàng)建的時候創(chuàng)建數(shù)據(jù)同步任務(wù)處理器ReplicationTaskProcessor沐序、創(chuàng)建批量任務(wù)調(diào)度器batchingDispatcher及創(chuàng)建單任務(wù)調(diào)度器nonBatchingDispatcher。
Eureka集群信息同步機(jī)制
?現(xiàn)在我們知道在注冊中心集群的各個節(jié)點中會存儲PeerEurekaNode對象,我們可以通過這些對象來同步各個節(jié)點的信息策幼,那么在這些集群節(jié)點信息之間又同步了些什么信息呢邑时。我們可以在PeerAwareInstanceRegistryImpl#register中看到在注冊之后有個replicateToPeers方法來同步節(jié)點信息,在這個方法中我們就看到了PeerEurekaNode對象特姐。
?在該方法中我們可以看到他通過一個isReplication參數(shù)來表示實例是否為復(fù)制的實例晶丘,通過這樣的方式來防止循環(huán)傳播。如果不是復(fù)制的實例并且存在eureka集群的話則會同步應(yīng)用名稱唐含、id浅浮、實例信息。
注冊中心剔除服務(wù)的機(jī)制什么
?在eureka中如果有些服務(wù)發(fā)生了錯誤捷枯,未正常在注冊中心中注銷滚秩,如果有服務(wù)調(diào)用到了這些服務(wù)就會導(dǎo)致業(yè)務(wù)無法進(jìn)行,這時該怎么辦铜靶。eureka為我們提供了服務(wù)剔除機(jī)制叔遂,主要用于剔除這些異常未正常調(diào)用cannel的服務(wù)他炊,主要通過EvictionTask中的evict方法來實現(xiàn)争剿。
?上圖就是evict的具體代碼,我們來詳細(xì)說下這里主要做了些什么操作:
- 首先他會判斷是否開啟了自我保護(hù)機(jī)制痊末,該機(jī)制在配置文件中配置蚕苇。
- 如果最后[更新時間 + lease的存活時間 + 補償時間 < 當(dāng)前時間]就加入到過期列表,補償時間的計算如下圖凿叠,計算方式[當(dāng)前時間點 - task最近一次執(zhí)行的時間點 - 清除間隔涩笤,小于0則取0]。
- 計算要剔除的注冊服務(wù)最大剔除數(shù)量盒件,計算方式為[注冊服務(wù)總數(shù)-注冊服務(wù)總數(shù)*自我保護(hù)續(xù)約百分比閥值]蹬碧,閥值來自配置文件默認(rèn)0.85。
- 通過洗牌算法(Knuth shuffle algorithm)算法來公平剔除服務(wù)炒刁。
- 服務(wù)剔除的方法如下圖恩沽,從服務(wù)容器中獲取該服務(wù)的實例,移除他翔始。將當(dāng)前服務(wù)剔除的操作時間添加到最近關(guān)閉服務(wù)隊列罗心、最近狀態(tài)更改隊列。最后清除緩存城瞎。
?因為自我保護(hù)機(jī)制的存在渤闷,會延遲才剔除服務(wù),所以我們需要對服務(wù)進(jìn)行降級和熔斷才能保證該服務(wù)盡量少調(diào)用或不調(diào)用脖镀。
服務(wù)消費者如何獲取服務(wù)信息
?注冊中心的作用我們清楚了飒箭,那么在服務(wù)調(diào)用的時候我們需要知道被調(diào)用服務(wù)器的信息,我們是如何在client中下載到其他服務(wù)器的信息呢。
?為了查找client的執(zhí)行痕跡弦蹂,我們需要把日志的級別修改debug漫萄,我們在client配置文件加上一條配置使日志打印出來[logging.level.root=DEBUG],加上之后我們再運行的時候就可以在注冊之后的信息看到如下圖的日志信息。
?根據(jù)打印的信息我們可以在對應(yīng)的日志信息中加上斷點查看調(diào)用鏈,通過調(diào)用鏈我們可以看到具體的刷新服務(wù)信息的邏輯盈匾。通過addInstance方法將服務(wù)信息添加到ConcurrentHashMap中腾务。
?至于如何初始化該刷新任務(wù)我們可以通過調(diào)用鏈之一向上可以找到下圖方法,在DiscoveryClient#initScheduledTasks方法中可以看到通過配置參數(shù)來設(shè)置定時執(zhí)行任務(wù)削饵。
eureka的作用總結(jié)
?注冊中心主要用于服務(wù)的注冊發(fā)現(xiàn)岩瘦,可以及時通過admin頁面來查看服務(wù)狀態(tài),方便運維人員及時處理異常服務(wù)器窿撬。