一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

深度剖析服務(wù)發(fā)現(xiàn)組件Netflix Eureka

 LZS2851 2016-12-26


一.背景介紹


Eureka是Netflix開源的一款提供服務(wù)注冊和發(fā)現(xiàn)的產(chǎn)品。其官方文檔中對自己的定義是:


Eureka is a REST (Representational State Transfer) based service that is primarily used in the AWS cloud for locating services for the purpose of load balancing and failover of middle-tier servers. We call this service, the Eureka Server. Eureka also comes with a Java-based client component,the Eureka Client, which makes interactions with the service much easier. The client also has a built-in load balancer that does basic round-robin load balancing.


我們在研發(fā)Apollo配置中心時(https://github.com/ctripcorp/apollo),考慮到配置中心是基礎(chǔ)服務(wù),有非常高的可用性要求,為了更好地支持服務(wù)動態(tài)擴(kuò)容、縮容、失效剔除等特性,所以就選擇了使用Eureka來提供服務(wù)注冊和發(fā)現(xiàn)功能。


本著“當(dāng)你選擇一款開源產(chǎn)品后,你就應(yīng)當(dāng)對它負(fù)責(zé),既要信任它又要挑戰(zhàn)它”的原則,我花了一些時間比較深入地研究了Eureka的實(shí)現(xiàn)細(xì)節(jié)(好在Eureka的實(shí)現(xiàn)短小精悍,通讀源碼也沒花太多時間),今天就來詳細(xì)介紹一下。


二.Why Eureka?


那么為什么我們在項(xiàng)目中使用了Eureka呢?我大致總結(jié)了一下,有以下幾方面的原因:


1. 它提供了完整的Service Registry和Service Discovery實(shí)現(xiàn)


首先是提供了完整的實(shí)現(xiàn),并且也經(jīng)受住了Netflix自己的生產(chǎn)環(huán)境考驗(yàn),相對使用起來會比較省心。


2. 和Spring Cloud無縫集成


我們的項(xiàng)目本身就使用了Spring Cloud和Spring Boot,同時Spring Cloud還有一套非常完善的開源代碼來整合Eureka,所以使用起來非常方便。


另外,Eureka還支持在我們應(yīng)用自身的容器中啟動,也就是說我們的應(yīng)用啟動完之后,既充當(dāng)了Eureka的角色,同時也是服務(wù)的提供者。這樣就極大地提高了服務(wù)的可用性。


這一點(diǎn)是我們選擇Eureka而不是zk、etcd等的主要原因,為了提高配置中心的可用性和降低部署復(fù)雜度,我們需要盡可能地減少外部依賴。


3. Open Source


最后一點(diǎn)是開源,由于代碼是開源的,所以非常便于我們了解它的實(shí)現(xiàn)原理和排查問題。


三.Dive into Eureka


相信大家看到這里,已經(jīng)對Eureka有了一個初步的認(rèn)識,接下來我們就來深入了解下它吧:


3.1 Overview


3.1.1 Basic Architecture


圖1


上圖簡要描述了Eureka的基本架構(gòu),由3個角色組成:


  • Eureka Server:提供服務(wù)注冊和發(fā)現(xiàn)

  • Service Provider:服務(wù)提供方,將自身服務(wù)注冊到Eureka,從而使服務(wù)消費(fèi)方能夠找到

  • Service Consumer:服務(wù)消費(fèi)方,從Eureka獲取注冊服務(wù)列表,從而能夠消費(fèi)服務(wù)。


需要注意的是,上圖中的3個角色都是邏輯角色。在實(shí)際運(yùn)行中,這幾個角色甚至可以是同一個實(shí)例,比如在我們項(xiàng)目中,Eureka Server和Service Provider就是同一個JVM進(jìn)程。


3.1.2 More in depth


圖2


上圖更進(jìn)一步的展示了3個角色之間的交互。


  • Service Provider會向Eureka Server做Register(服務(wù)注冊)、Renew(服務(wù)續(xù)約)、Cancel(服務(wù)下線)等操作;

  • Eureka Server之間會做注冊服務(wù)的同步,從而保證狀態(tài)一致;

  • Service Consumer會向Eureka Server獲取注冊服務(wù)列表,并消費(fèi)服務(wù)。


3.2 Demo


為了給大家一個更直觀的印象,我們可以通過一個簡單的demo來實(shí)際運(yùn)行一下,從而對Eureka有更好的了解。


3.2.1 Git Repository


Git倉庫:https://github.com/nobodyiam/spring-cloud-in-action


這個項(xiàng)目使用了Spring Cloud相關(guān)類庫,包括:


  • Spring Cloud Config

  • Spring Cloud Eureka (Netflix)


3.2.2 準(zhǔn)備工作


Demo項(xiàng)目使用了Spring Cloud Config做配置,所以第一步先在本地啟動Config Server。


由于項(xiàng)目基于Spring Boot開發(fā),所以直接運(yùn)行com.nobodyiam.spring.cloud.in.action.config.ConfigServerApplication即可。


3.2.3 Eureka Server Demo


Eureka Server的Demo模塊名是:eureka-server。


  • Maven依賴


eureka-server是一個基于Spring Boot的Web應(yīng)用,我們首先需要做的就是在pom中引入Spring Cloud Eureka Server的依賴。


    org.springframework.cloud

    spring-cloud-starter-eureka-server

    1.2.0.RELEASE


  • 啟用Eureka Server


啟用Eureka Server非常簡單,只需要加上@EnableEurekaServer即可。


@EnableEurekaServer

@SpringBootApplication

public class EurekaServiceApplication {

  public static void main(String[] args) {

    SpringApplication.run(EurekaServiceApplication.class, args);

  }

}


做完以上配置后,啟動應(yīng)用,Eureka Server就開始工作了!啟動完,打開http://localhost:8761,就能看到啟動成功的畫面了。


圖3


3.2.4 Service Provider and Service Consumer Demo


Service Provider的Demo模塊名是:reservation-service。 

Service Consumer的Demo模塊名是:reservation-client。


  • Maven依賴


reservation-service和reservation-client都是基于Spring Boot的Web應(yīng)用,我們首先需要做的就是在pom中引入Spring Cloud Eureka的依賴。


    org.springframework.cloud

    spring-cloud-starter-eureka

    1.2.0.RELEASE


  • 啟動Service Provider


啟用Service Provider非常簡單,只需要加上@EnableDiscoveryClient即可。


@EnableDiscoveryClient

@SpringBootApplication

public class ReservationServiceApplication {

  public static void main(String[] args) {

    new SpringApplicationBuilder(ReservationServiceApplication.class)

            .run(args);

  }

}


做完以上配置后,啟動應(yīng)用,Server Provider就開始工作了! 啟動完,打開http://localhost:8761,就能看到服務(wù)已經(jīng)注冊到Eureka Server了。


圖4


  • 啟動Service Consumer


啟動Service Consumer其實(shí)和Service Provider一樣,因?yàn)楸举|(zhì)上Eureka提供的客戶端是不區(qū)分Provider和Consumer的,一般情況下,Provider同時也會是Consumer。


@EnableDiscoveryClient

@SpringBootApplication

public class ReservationClientApplication {

  @Bean

  CommandLineRunner runner(DiscoveryClient dc) {

    return args -> {

      dc.getInstances('reservation-service')

              .forEach(si -> System.out.println(String.format(

                      'Found %s %s:%s', si.getServiceId(), si.getHost(), si.getPort())));

    };

  }

  public static void main(String[] args) {

    SpringApplication.run(ReservationClientApplication.class, args);

  }

}


上述代碼中通過dc.getInstances('reservation-service')就能獲取到當(dāng)前所有注冊的reservation-service服務(wù)。


3.3 Eureka Server實(shí)現(xiàn)細(xì)節(jié)


看了前面的demo,我們已經(jīng)初步領(lǐng)略到了Spring Cloud和Eureka的強(qiáng)大之處,通過短短幾行配置就實(shí)現(xiàn)了服務(wù)注冊和發(fā)現(xiàn)!


相信大家一定想了解Eureka是如何實(shí)現(xiàn)的吧,所以接下來我們繼續(xù)Dive!首先來看下Eureka Server的幾個對外接口實(shí)現(xiàn)。


3.3.1 Register


首先來看Register(服務(wù)注冊),這個接口會在Service Provider啟動時被調(diào)用來實(shí)現(xiàn)服務(wù)注冊。同時,當(dāng)Service Provider的服務(wù)狀態(tài)發(fā)生變化時(如自身檢測認(rèn)為Down的時候),也會調(diào)用來更新服務(wù)狀態(tài)。


接口實(shí)現(xiàn)比較簡單,如下圖所示。


  • ApplicationResource類接收Http服務(wù)請求,調(diào)用PeerAwareInstanceRegistryImpl的register方法

  • PeerAwareInstanceRegistryImpl完成服務(wù)注冊后,調(diào)用replicateToPeers向其它Eureka Server節(jié)點(diǎn)(Peer)做狀態(tài)同步(異步操作)


圖5


注冊的服務(wù)列表保存在一個嵌套的hash map中:


  • 第一層hash map的key是app name,也就是應(yīng)用名字

  • 第二層hash map的key是instance name,也就是實(shí)例名字


以3.2.4.2中的截圖為例,RESERVATION-SERVICE就是app name,jason-mbp.lan:reservation-service:8000就是instance name。


Hash map定義如下:


private final ConcurrentHashMap>> registry =

new ConcurrentHashMap>>();


3.3.2 Renew


Renew(服務(wù)續(xù)約)操作由Service Provider定期調(diào)用,類似于heartbeat。主要是用來告訴Eureka Server Service Provider還活著,避免服務(wù)被剔除掉。接口實(shí)現(xiàn)如下圖所示。


可以看到,接口實(shí)現(xiàn)方式和register基本一致:首先更新自身狀態(tài),再同步到其它Peer。


圖6


3.3.3 Cancel


Cancel(服務(wù)下線)一般在Service Provider shut down的時候調(diào)用,用來把自身的服務(wù)從Eureka Server中刪除,以防客戶端調(diào)用不存在的服務(wù)。接口實(shí)現(xiàn)如下圖所示。


圖7


3.3.4 Fetch Registries


Fetch Registries由Service Consumer調(diào)用,用來獲取Eureka Server上注冊的服務(wù)。為了提高性能,服務(wù)列表在Eureka Server會緩存一份,同時每30秒更新一次。


圖8


3.3.5 Eviction


Eviction(失效服務(wù)剔除)用來定期(默認(rèn)為每60秒)在Eureka Server檢測失效的服務(wù),檢測標(biāo)準(zhǔn)就是超過一定時間沒有Renew的服務(wù)。


默認(rèn)失效時間為90秒,也就是如果有服務(wù)超過90秒沒有向Eureka Server發(fā)起Renew請求的話,就會被當(dāng)做失效服務(wù)剔除掉。


失效時間可以通過eureka.instance.leaseExpirationDurationInSeconds進(jìn)行配置,定期掃描時間可以通過eureka.server.evictionIntervalTimerInMs進(jìn)行配置。


接口實(shí)現(xiàn)邏輯見下圖:


圖9


3.3.6 How Peer Replicates


在前面的Register、Renew、Cancel接口實(shí)現(xiàn)中,我們看到了都會有replicateToPeers操作,這個就是用來做Peer之間的狀態(tài)同步。


通過這種方式,Service Provider只需要通知到任意一個Eureka Server后就能保證狀態(tài)會在所有的Eureka Server中得到更新。


具體實(shí)現(xiàn)方式其實(shí)很簡單,就是接收到Service Provider請求的Eureka Server,把請求再次轉(zhuǎn)發(fā)到其它的Eureka Server,調(diào)用同樣的接口,傳入同樣的參數(shù),除了會在header中標(biāo)記isReplication=true,從而避免重復(fù)的replicate。


Peer之間的狀態(tài)是采用異步方式同步的,所以不保證節(jié)點(diǎn)間的狀態(tài)一定是一致的,不過基本能保證最終狀態(tài)是一致的。


結(jié)合服務(wù)發(fā)現(xiàn)的場景,實(shí)際上也并不需要節(jié)點(diǎn)間的狀態(tài)強(qiáng)一致。在一段時間內(nèi)(比如30秒),節(jié)點(diǎn)A比節(jié)點(diǎn)B多一個服務(wù)實(shí)例或少一個服務(wù)實(shí)例,在業(yè)務(wù)上也是完全可以接受的(Service Consumer側(cè)一般也會實(shí)現(xiàn)錯誤重試和負(fù)載均衡機(jī)制)。


所以按照CAP理論,Eureka的選擇就是放棄C,選擇AP。


3.3.7 How Peer Nodes are Discovered


那大家可能會有疑問,Eureka Server是怎么知道有多少Peer的呢?


Eureka Server在啟動后會調(diào)用EurekaClientConfig.getEurekaServerServiceUrls來獲取所有的Peer節(jié)點(diǎn),并且會定期更新。定期更新頻率可以通過eureka.server.peerEurekaNodesUpdateIntervalMs配置。


這個方法的默認(rèn)實(shí)現(xiàn)是從配置文件讀取,所以如果Eureka Server節(jié)點(diǎn)相對固定的話,可以通過在配置文件中配置來實(shí)現(xiàn)。


如果希望能更靈活的控制Eureka Server節(jié)點(diǎn),比如動態(tài)擴(kuò)容/縮容,那么可以override getEurekaServerServiceUrls方法,提供自己的實(shí)現(xiàn),比如我們的項(xiàng)目中會通過數(shù)據(jù)庫讀取Eureka Server列表。


具體實(shí)現(xiàn)如下圖所示:


圖10


3.3.8 How New Peer Initializes


最后再來看一下一個新的Eureka Server節(jié)點(diǎn)加進(jìn)來,或者Eureka Server重啟后,如何來做初始化,從而能夠正常提供服務(wù)。


具體實(shí)現(xiàn)如下圖所示,簡而言之就是啟動時把自己當(dāng)做是Service Consumer從其它Peer Eureka獲取所有服務(wù)的注冊信息。然后對每個服務(wù),在自己這里執(zhí)行Register,isReplication=true,從而完成初始化。


圖11


3.4 Service Provider實(shí)現(xiàn)細(xì)節(jié)


現(xiàn)在來看下Service Provider的實(shí)現(xiàn)細(xì)節(jié),主要就是Register、Renew、Cancel這3個操作。


3.4.1 Register


Service Provider要對外提供服務(wù),一個很重要的步驟就是把自己注冊到Eureka Server上。


這部分的實(shí)現(xiàn)比較簡單,只需要在啟動時和實(shí)例狀態(tài)變化時調(diào)用Eureka Server的接口注冊即可。需要注意的是,需要確保配置eureka.client.registerWithEureka=true。


圖12


3.4.2 Renew


Renew操作會在Service Provider端定期發(fā)起,用來通知Eureka Server自己還活著。這里有兩個比較重要的配置需要注意一下:


  • eureka.instance.leaseRenewalIntervalInSeconds 

    Renew頻率。默認(rèn)是30秒,也就是每30秒會向Eureka Server發(fā)起Renew操作;

  • eureka.instance.leaseExpirationDurationInSeconds 

    服務(wù)失效時間。默認(rèn)是90秒,也就是如果Eureka Server在90秒內(nèi)沒有接收到來自Service Provider的Renew操作,就會把Service Provider剔除。


具體實(shí)現(xiàn)如下:


圖13


3.4.3 Cancel


在Service Provider服務(wù)shut down的時候,需要及時通知Eureka Server把自己剔除,從而避免客戶端調(diào)用已經(jīng)下線的服務(wù)。邏輯本身比較簡單,通過對方法標(biāo)記@PreDestroy,從而在服務(wù)shut down的時候會被觸發(fā)。


圖14


3.4.4 How Eureka Servers are Discovered


這里大家疑問又來了,Service Provider是怎么知道Eureka Server的地址呢?其實(shí)這部分的主體邏輯和3.3.7 How Peer Nodes are Discovered幾乎是一樣的。


也是默認(rèn)從配置文件讀取,如果需要更靈活的控制,可以通過override getEurekaServerServiceUrls方法來提供自己的實(shí)現(xiàn)。定期更新頻率可以通過eureka.client.eurekaServiceUrlPollIntervalSeconds配置。


圖15


3.5 Service Consumer實(shí)現(xiàn)細(xì)節(jié)


Service Consumer這塊的實(shí)現(xiàn)相對就簡單一些,因?yàn)樗簧婕暗綇腅ureka Server獲取服務(wù)列表和更新服務(wù)列表。


3.5.1 Fetch Service Registries


Service Consumer在啟動時會從Eureka Server獲取所有服務(wù)列表,并在本地緩存。需要注意的是,需要確保配置eureka.client.shouldFetchRegistry=true。


圖16


3.5.2 Update Service Registries


由于在本地有一份緩存,所以需要定期更新,定期更新頻率可以通過eureka.client.registryFetchIntervalSeconds配置。


圖17


3.5.3 How Eureka Servers are Discovered


Service Consumer和Service Provider一樣,也有一個如何知道Eureka Server地址的問題。


其實(shí)由于Service Consumer和Service Provider本質(zhì)上是同一個Eureka客戶端,所以這部分邏輯是一樣的,這里就不再贅述了。詳細(xì)信息見3.4.4節(jié)。


四.Summary


本文主要介紹了Eureka的實(shí)現(xiàn)思路,通過深入了解Eureka Server、Service Provider、Service Consumer的實(shí)現(xiàn),我們清晰地看到了服務(wù)注冊、發(fā)現(xiàn)的一系列過程和實(shí)現(xiàn)方式。


相信對正在使用Eureka的同學(xué)會有一些幫助,同時希望對暫不使用Eureka的同學(xué)也能有一定的啟發(fā),畢竟服務(wù)注冊、發(fā)現(xiàn)還是比較基礎(chǔ)和通用的,了解了實(shí)現(xiàn)方式后,在使用上應(yīng)該能更得心應(yīng)手一些吧。

作者:宋順,攜程框架研發(fā)部技術(shù)專家。2016年初加入攜程,主要負(fù)責(zé)中間件產(chǎn)品的相關(guān)研發(fā)工作。畢業(yè)于復(fù)旦大學(xué)軟件工程系,曾就職于大眾點(diǎn)評,擔(dān)任后臺系統(tǒng)技術(shù)負(fù)責(zé)人。 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    熟女一区二区三区国产| 国产欧美日韩精品成人专区| 欧美尤物在线视频91| 又色又爽又无遮挡的视频| 亚洲av专区在线观看| 亚洲欧美日韩精品永久| 国产免费人成视频尤物| 亚洲a级一区二区不卡| 日韩一区二区三区久久| 国产日韩精品欧美综合区| 欧美午夜一区二区福利视频| av在线免费观看在线免费观看| 黄色片国产一区二区三区| 日本人妻熟女一区二区三区| 最近日韩在线免费黄片| 老熟妇2久久国内精品| 国产一区二区三区av在线| 成人免费在线视频大香蕉| 午夜精品国产精品久久久| 一区二区日韩欧美精品| 欧美日韩国产自拍亚洲| 白丝美女被插入视频在线观看| 日韩欧美91在线视频| 欧美日韩一区二区三区色拉拉| 免费一区二区三区少妇| 美国女大兵激情豪放视频播放| 成人精品欧美一级乱黄| 人妻精品一区二区三区视频免精 | 成人午夜在线视频观看| 国产不卡一区二区四区| 日韩欧美国产亚洲一区| 中文字幕久热精品视频在线| 丰满少妇被粗大猛烈进出视频 | 高清免费在线不卡视频| 国产免费一区二区三区av大片| 国产毛片对白精品看片| 乱女午夜精品一区二区三区| 亚洲av秘片一区二区三区| 午夜资源在线观看免费高清| 内射精子视频欧美一区二区| 91精品欧美综合在ⅹ|