成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

spring-cloud-eureka服務(wù)治理

Clect / 1507人閱讀

摘要:服務(wù)續(xù)約在服務(wù)注冊完成之后,服務(wù)提供者需要維護(hù)一個(gè)心跳來告知注冊中心服務(wù)實(shí)例處于正常運(yùn)行狀態(tài)中,防止注冊中心將正常的服務(wù)實(shí)例剔除出注冊中心。

Spring Cloud Eureka 目錄

前言

構(gòu)建服務(wù)注冊中心

服務(wù)注冊與發(fā)現(xiàn)

Eureka的基礎(chǔ)架構(gòu)

Eureka的服務(wù)治理機(jī)制

Eureka的配置

代碼地址

前言 服務(wù)治理

?隨著微服務(wù)應(yīng)用的不斷增加,靜態(tài)配置會越來越難以維護(hù),并且隨著業(yè)務(wù)的不斷發(fā)展,集群規(guī)模、服務(wù)位置、服務(wù)命名都會發(fā)生變化,手動(dòng)維護(hù)的方式極易發(fā)生錯(cuò)誤或是命名沖突問題。因此需要服務(wù)治理框架對微服務(wù)實(shí)例進(jìn)行管理,服務(wù)治理是微服務(wù)架構(gòu)中最核心的功能和模塊,主要用來各個(gè)微服務(wù)實(shí)例的自動(dòng)化注冊和發(fā)現(xiàn)。

服務(wù)注冊

?在服務(wù)治理框架中,通常都會有一個(gè)服務(wù)注冊中心。

?每一個(gè)微服務(wù)實(shí)例向注冊中心登記自己提供的服務(wù),將主機(jī)、端口號、版本號、通信協(xié)議等一些信息告知注冊中心。

?注冊中心按服務(wù)名分類組織服務(wù)清單。

?服務(wù)注冊中心需要以心跳的方式監(jiān)測服務(wù)清單中的服務(wù)是否可用,如果不可用,需要將不可用的服務(wù)實(shí)例進(jìn)行剔除。

服務(wù)發(fā)現(xiàn)

?服務(wù)間的調(diào)用通過向服務(wù)名發(fā)起請求調(diào)用實(shí)現(xiàn)。 服務(wù)調(diào)用方在調(diào)用提供方的接口時(shí),并不知道提供方的具體地址。

?服務(wù)調(diào)用方需要從注冊中心獲取所有服務(wù)的實(shí)例清單,才可以實(shí)現(xiàn)對具體服務(wù)實(shí)例的訪問。

?服務(wù)調(diào)用方在發(fā)起調(diào)用時(shí),會以某種策略取出一個(gè)具體的服務(wù)實(shí)例進(jìn)行服務(wù)調(diào)用(客戶端負(fù)載均衡)。

?在實(shí)際的環(huán)境中,為了提供性能,并不會采用每次都向服務(wù)注冊中心獲取服務(wù)的方式進(jìn)行服務(wù)的調(diào)用,并且不同的應(yīng)用場景在緩存和服務(wù)剔除等機(jī)制上可以采用不同的實(shí)現(xiàn)策略。

Netflix Eureka

?Spring Cloud Eureka采用Netflix Eureka來實(shí)現(xiàn)服務(wù)注冊與發(fā)現(xiàn),包含客戶端服務(wù)端組件。

Eureka服務(wù)端(服務(wù)注冊中心)

?支持高可用配置。

?依托于強(qiáng)一致性提供良好的服務(wù)實(shí)例可用性。

?服務(wù)注冊中心之間可以通過異步模式互相復(fù)制各自的狀態(tài)。

Eureka客戶端

?主要用于服務(wù)的注冊和發(fā)現(xiàn)。

?客戶端可以通過注解和參數(shù)配置的方式實(shí)現(xiàn)注冊與發(fā)現(xiàn)。

?Eureka客戶端向注冊中心注冊自身提供的服務(wù)并周期性地發(fā)送心跳來更新它的服務(wù)租約。

?Eureka客戶端從服務(wù)端查詢當(dāng)前注冊的服務(wù)信息并把它們緩存到本地并周期性的刷新服務(wù)狀態(tài)。

構(gòu)建服務(wù)注冊中心 構(gòu)建注冊中心(位于spring-eureka-server的Module下)
package cn.sh.eureka.server; //代碼位于該包下

1.準(zhǔn)備pom.xml

    
    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.3.RELEASE
            
    
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka-server
            1.2.7.RELEASE
        
    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Finchley.RELEASE
                pom
                import
            
        
    

2.準(zhǔn)備配置文件application.properties

#端口號
server.port=9000

eureka.instance.hostname=localhost

#禁止注冊中心注冊自己
eureka.client.register-with-eureka=false

#禁止注冊中心搜索服務(wù)
eureka.client.fetch-registry=false

eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

3.編寫注冊中心代碼(@EnableEurekaServer)

package cn.sh.eureka.server;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @author sh
 * @EnableEurekaServer 啟動(dòng)一個(gè)注冊中心
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServer {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServer.class, args);
    }
}
構(gòu)建微服務(wù)應(yīng)用(服務(wù)提供者)

1.準(zhǔn)備pom.xml

    
    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.0.3.RELEASE
    
    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
        
            org.springframework.cloud
            spring-cloud-starter-eureka
            1.2.5.RELEASE
        
    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                Finchley.RELEASE
                pom
                import
            
        
    

2.準(zhǔn)備配置文件application.properties

#端口號
server.port=8000

#服務(wù)名稱
spring.application.name=produce-service

#服務(wù)注冊中心地址
eureka.client.serviceUrl.defaultZone=http://localhost:9000/eureka/

3.編寫produce-service服務(wù)的代碼

代碼位于spring-cloud-eureka-client模塊下

package cn.sh.eureka.produce; //代碼包位置
高可用注冊中心搭建

?Eureka Server的高可用實(shí)際上就是講自己作為服務(wù)向其他服務(wù)注冊中心注冊自己,這樣可以形成一組互相注冊的服務(wù)注冊中心,以實(shí)現(xiàn)服務(wù)清單的互相同步,達(dá)到高可用的效果。

?相關(guān)實(shí)現(xiàn)在spring-cloud-eureka-server模塊下,注意在host配置文件中配置peer1和peer2的轉(zhuǎn)換

?將代碼通過maven編譯成jar包

?通過java命令啟動(dòng)兩個(gè)注冊中心

java -jar spring-cloud-eureka-server-1.0.jar --spring.profiles.active=peer1
java -jar spring-cloud-eureka-server-1.0.jar --spring.profiles.active=peer2

?啟動(dòng)之后,會發(fā)現(xiàn)在注冊中心peer1的面板上的available-replicas中出現(xiàn)http://peer2:9002/eureka/,同樣,在注冊中心peer2面板上的available-replicas中出現(xiàn)http://peer1:9001/eureka/

eureka.instance.prefer-ip-address=true, 使用IP地址的方式指定注冊中心的地址,默認(rèn)false,以主機(jī)名定義注冊中心地址

服務(wù)發(fā)現(xiàn)與消費(fèi)

?服務(wù)消費(fèi)者的主要目標(biāo)是發(fā)現(xiàn)和消費(fèi)服務(wù)。其中服務(wù)發(fā)現(xiàn)由Eureka客戶端完成,服務(wù)消費(fèi)由Ribbon完成。

Ribbon簡單介紹

?Ribbon是一個(gè)基于HTTP和TCP的客戶端負(fù)載均衡器,它可以通過在客戶端中配置的ribbonServerList服務(wù)實(shí)例列表去輪詢訪問以達(dá)到負(fù)載均衡的作用。

?Ribbon與Eureka結(jié)合使用時(shí),ribbonServerList服務(wù)實(shí)例列表會被DiscoveryEnabledNIWSServerList重寫,擴(kuò)展成從Eureka注冊中心中獲取服務(wù)列表。

?Ribbon與Eureka結(jié)合使用時(shí),采用NIWSDiscoveryPing取代IPing,它將職責(zé)委托給Eureka來確定服務(wù)實(shí)例是否啟動(dòng)。

構(gòu)建消費(fèi)者

1.pom.xml

?增加對Ribbon的支持

    
        org.springframework.cloud
        spring-cloud-starter-ribbon
        1.2.7.RELEASE
    

2.相關(guān)代碼在spring-cloud-eureka-consumer模塊下

Eureka詳解 基礎(chǔ)結(jié)構(gòu)

服務(wù)注冊中心:Eureka服務(wù)端,提供服務(wù)注冊和發(fā)現(xiàn)的功能

服務(wù)提供者:提供服務(wù)的應(yīng)用,將自己提供的服務(wù)注冊到Eureka,供其他應(yīng)用發(fā)現(xiàn)

服務(wù)消費(fèi)者:消費(fèi)者從注冊中心發(fā)現(xiàn)服務(wù)列表,然后調(diào)用對應(yīng)的服務(wù)(Ribbon或Feign)

備注: 一般一個(gè)應(yīng)用既是服務(wù)提供者也是服務(wù)消費(fèi)者。

服務(wù)治理機(jī)制

?Eureka服務(wù)體系圖

服務(wù)提供者
服務(wù)注冊

?服務(wù)提供者會以Rest請求的方式注冊到注冊中心上,在請求過程中會攜帶自身的一些元數(shù)據(jù)信息。注冊中心在收到請求后,會將元數(shù)據(jù)信息保存到一個(gè)雙層Map結(jié)構(gòu)中,外層的key是服務(wù)名稱,內(nèi)層的key是具體的服務(wù)實(shí)例名稱。

?eureka.client.register-with-eureka,如果該參數(shù)的值等于false,不會進(jìn)行注冊。

服務(wù)同步

?如果兩個(gè)服務(wù)注冊在兩個(gè)不同的注冊中心上,兩個(gè)注冊中心互相注冊成為服務(wù)(集群),此時(shí),當(dāng)服務(wù)提供者向其中一個(gè)注冊中心發(fā)起請求時(shí),該注冊中心會將請求準(zhǔn)發(fā)給集群中的其他注冊中心,從而實(shí)現(xiàn)注冊中心之間的服務(wù)同步。

?由于服務(wù)同步的存在,服務(wù)提供者的信息可以在任意一臺注冊中心上獲取。

服務(wù)續(xù)約

?在服務(wù)注冊完成之后,服務(wù)提供者需要維護(hù)一個(gè)心跳來告知注冊中心服務(wù)實(shí)例處于正常運(yùn)行狀態(tài)中,防止注冊中心將正常的服務(wù)實(shí)例剔除出注冊中心。上述操作就成為服務(wù)續(xù)約。

屬性 含義
eureka.instance.lease-renewal-interval-in-seconds 服務(wù)續(xù)約任務(wù)調(diào)用的間隔時(shí)間,默認(rèn)時(shí)間30s
eureka.instance.lease-expiration-duration-in-seconds 服務(wù)失效時(shí)間(表示注冊中心至上一次收到客戶端的心跳之后,等待下一次心跳的超時(shí)時(shí)間,在這個(gè)時(shí)間內(nèi)若沒收到下一次心跳,則將移除該客戶端實(shí)例),默認(rèn)90s
服務(wù)消費(fèi)者
獲取服務(wù)

?啟動(dòng)服務(wù)消費(fèi)者時(shí),服務(wù)消費(fèi)者會向注冊中心發(fā)起一個(gè)Rest請求,來獲取注冊中心維護(hù)的服務(wù)實(shí)例清單。但是為了提高性能,注冊中心會維護(hù)一份只讀的服務(wù)清單返回給客戶端,該緩存的服務(wù)清單會每隔30s刷新一次。

?eureka.client.fetch-registry,如果該參數(shù)被設(shè)置為false,無法向注冊中心獲取服務(wù)清單。

?eureka.client.registry-fetch-interval-seconds,緩存清單的刷新時(shí)間,默認(rèn)30s。

服務(wù)調(diào)用

?服務(wù)消費(fèi)者獲得服務(wù)清單后,可以根據(jù)服務(wù)名獲取具體服務(wù)實(shí)例列表(元數(shù)據(jù)信息),根據(jù)自己的策略選擇具體的服務(wù)實(shí)例進(jìn)行調(diào)用。

?Eureka有Region和Zone的概念,一個(gè)Region中會有多個(gè)Zone,每個(gè)客戶端都需要注冊到一個(gè)Zone中,所以客戶端對應(yīng)一個(gè)Region和一個(gè)Zone。在服務(wù)進(jìn)行調(diào)用時(shí),優(yōu)先訪問同一個(gè)Zone中的服務(wù)提供方,若訪問不到,再訪問其他Zone。

服務(wù)下線

?當(dāng)服務(wù)實(shí)例正常關(guān)閉時(shí),服務(wù)實(shí)例會發(fā)送一個(gè)服務(wù)下線的Rest請求給注冊中心。注冊中心在收到請求后,會將該服務(wù)實(shí)例的狀態(tài)置為DOWN,并且將下線時(shí)間廣播出去。

服務(wù)注冊中心
失效剔除

?當(dāng)服務(wù)實(shí)例未正常下線時(shí)(內(nèi)存溢出、網(wǎng)絡(luò)故障),服務(wù)注冊中心未能收到服務(wù)下線的Rest請求。注冊中心在啟動(dòng)時(shí)會創(chuàng)建一個(gè)定時(shí)任務(wù),默認(rèn)每隔一段時(shí)間(60s)將當(dāng)前清單中超時(shí)(服務(wù)失效時(shí)間,默認(rèn)90s)沒有續(xù)約的服務(wù)進(jìn)行剔除。

自我保護(hù)

?注冊中心在運(yùn)行期間,會統(tǒng)計(jì)心跳失敗比例在15分鐘內(nèi)是否低于85%,如果出現(xiàn)低于的情況,注冊中心會將當(dāng)前服務(wù)實(shí)例的注冊信息保護(hù)起來,讓這些實(shí)例不會過期。但是,在保護(hù)期時(shí)間內(nèi),如果實(shí)例出現(xiàn)問題,那么服務(wù)調(diào)用者很容易拿到該實(shí)例調(diào)用失敗,所以服務(wù)調(diào)用者必須要有容錯(cuò)機(jī)制(請求重試、斷路由器等)。

?eureka.server.enable-self-preservation,如果該值設(shè)置為false,則不啟用自我保護(hù)機(jī)制,默認(rèn)值為true

源碼分析

?分析源碼,可以以Eureka客戶端和Eureka服務(wù)端作為切入點(diǎn)。

Eureka客戶端

在應(yīng)用獲取服務(wù)列表和向注冊中心注冊成為服務(wù)時(shí)只做了兩件事:

在啟動(dòng)類上使用@EnableEurekaClient或者@EnableDiscoveryClient注解

在application.properties中添加eureka.client.serviceUrl.defaultZone

@EurekaDiscoveryClient

?該注解的主要作用是用來開啟一個(gè)DiscoveryClient的實(shí)例。

org.springframework.cloud.client.discovery.DiscoveryClient類

?類圖以后補(bǔ)充

作用
org.springframework.cloud.client.discovery.DiscoveryClient Spring Cloud的接口,定義了發(fā)現(xiàn)服務(wù)的常用抽象方法,這樣做的好處是可以屏蔽服務(wù)治理的細(xì)節(jié),可以方便的切換不同的服務(wù)治理框架,不需要改動(dòng)程序代碼,只需要添加一些針對服務(wù)治理框架的配置
com.netflix.appinfo.InstanceInfo.LookupService 定義了Eureka發(fā)現(xiàn)服務(wù)的抽象方法
com.netflix.discovery.EurekaClient 定義了Eureka發(fā)現(xiàn)服務(wù)的抽象方法,繼承LookupService
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient Spring中的DiscoveryClient接口的實(shí)現(xiàn),對Eureka發(fā)現(xiàn)服務(wù)的封裝,實(shí)現(xiàn)EurekaClient接口,Eureka接口繼承LookupService接口
com.netflix.discovery.DiscoveryClient 實(shí)現(xiàn)EurekaClient接口,真正的服務(wù)發(fā)現(xiàn)實(shí)現(xiàn)類
com.netflix.discovery.DiscoveryClient類

通過頭部的注釋信息,我們可以得到以下信息:

1.DiscoveryClient類主要用于幫助客戶端和注冊中心互相協(xié)作。

2.Eureka客戶端主要負(fù)責(zé)的任務(wù):

向注冊中心注冊服務(wù)實(shí)例

向注冊中心進(jìn)行服務(wù)租約

當(dāng)服務(wù)關(guān)閉期間,向注冊中心取消租約

查詢注冊中心的服務(wù)實(shí)例列表

3.Eureka客戶端需要配置一個(gè)注冊中心的URL列表

Eureka客戶端注冊中心URL列表進(jìn)行配置

?關(guān)鍵類:com.netflix.discovery.endpoint.EndpointUtils

?關(guān)鍵方法:Map> getServiceUrlsMapFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone)

    /**
     * Get the list of all eureka service urls from properties file for the eureka client to talk to.
     *
     * @param clientConfig the clientConfig to use
     * @param instanceZone The zone in which the client resides
     * @param preferSameZone true if we have to prefer the same zone as the client, false otherwise
     * @return an (ordered) map of zone -> list of urls mappings, with the preferred zone first in iteration order
     */
    public static Map> getServiceUrlsMapFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) {
        Map> orderedUrls = new LinkedHashMap<>();
        String region = getRegion(clientConfig);
        String[] availZones = clientConfig.getAvailabilityZones(clientConfig.getRegion());
        if (availZones == null || availZones.length == 0) {
            availZones = new String[1];
            availZones[0] = DEFAULT_ZONE;
        }
        logger.debug("The availability zone for the given region {} are {}", region, availZones);
        int myZoneOffset = getZoneOffset(instanceZone, preferSameZone, availZones);

        String zone = availZones[myZoneOffset];
        List serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
        if (serviceUrls != null) {
            orderedUrls.put(zone, serviceUrls);
        }
        int currentOffset = myZoneOffset == (availZones.length - 1) ? 0 : (myZoneOffset + 1);
        while (currentOffset != myZoneOffset) {
            zone = availZones[currentOffset];
            serviceUrls = clientConfig.getEurekaServerServiceUrls(zone);
            if (serviceUrls != null) {
                orderedUrls.put(zone, serviceUrls);
            }
            if (currentOffset == (availZones.length - 1)) {
                currentOffset = 0;
            } else {
                currentOffset++;
            }
        }

        if (orderedUrls.size() < 1) {
            throw new IllegalArgumentException("DiscoveryClient: invalid serviceUrl specified!");
        }
        return orderedUrls;
    }

1.加載Region、Zone

?通過getRegion函數(shù),從配置文件中讀取一個(gè)Region返回,所以一個(gè)微服務(wù)應(yīng)用只能屬于一個(gè)Region,如果不進(jìn)行配置,默認(rèn)值default,eureka.client.region該屬性可以配置Region

?通過getAvailabilityZones函數(shù),如果沒有為Region配置Zone,默認(rèn)值是defaultZone,因此注冊中心URL列表的默認(rèn)配置參數(shù)為eureka.client.serviceUrl.defaultZone。eureka.client.availability-zone.可以配置Region下面的Zone,Zone的配置有多個(gè)(用,分隔)。

2.加載serviceUrls

?按照一定的方法以此加載每個(gè)Zone中的urls,存放在一個(gè)Map>中。

?當(dāng)使用Ribbon來調(diào)用服務(wù)時(shí),Ribbon的默認(rèn)策略是優(yōu)先訪問和客戶端處于同一個(gè)Zone的微服務(wù)實(shí)例。

?在獲取到客戶端配置的serviceUrls之后,就可以進(jìn)行服務(wù)的注冊,詳情請看下面。

向注冊中心注冊服務(wù)(服務(wù)注冊)

?關(guān)鍵類:com.netflix.discovery.DiscoveryClient

?關(guān)鍵方法:void initScheduledTasks(),DiscoveryClient的構(gòu)造函數(shù)會對此方法進(jìn)行調(diào)用

?該方法主要用來啟用定時(shí)任務(wù),主要包括獲取服務(wù)Task、服務(wù)注冊、服務(wù)續(xù)約(心跳),本次先著重看服務(wù)注冊的邏輯

    /**
     * Initializes all scheduled tasks.
     */
    private void initScheduledTasks() {
        
        //此處是該方法的其他邏輯
        
        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);

            // Heartbeat timer
            
            // InstanceInfo replicator
            instanceInfoReplicator = new InstanceInfoReplicator(
                    this,
                    instanceInfo,
                    clientConfig.getInstanceInfoReplicationIntervalSeconds(),
                    2); // burstSize

            statusChangeListener = new ApplicationInfoManager.StatusChangeListener() {
                @Override
                public String getId() {
                    return "statusChangeListener";
                }

                @Override
                public void notify(StatusChangeEvent statusChangeEvent) {
                    if (InstanceStatus.DOWN == statusChangeEvent.getStatus() ||
                            InstanceStatus.DOWN == statusChangeEvent.getPreviousStatus()) {
                        // log at warn level if DOWN was involved
                        logger.warn("Saw local status change event {}", statusChangeEvent);
                    } else {
                        logger.info("Saw local status change event {}", statusChangeEvent);
                    }
                    instanceInfoReplicator.onDemandUpdate();
                }
            };

            if (clientConfig.shouldOnDemandUpdateStatusChange()) {
                applicationInfoManager.registerStatusChangeListener(statusChangeListener);
            }

            instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
        } else {
            logger.info("Not registering with Eureka server per configuration");
        }
    }

1.判斷是否允許客戶端向注冊中心注冊

?eureka.client.register-with-eureka 該參數(shù)要設(shè)置成true,默認(rèn)值為true

?如果上述參數(shù)值為true,則執(zhí)行注冊任務(wù)

2.新建InstanceInfoReplicator,利用其來進(jìn)行注冊

?該類實(shí)現(xiàn)了Runnable接口,觀察run方法,在進(jìn)行注冊時(shí)實(shí)際調(diào)用的是com.netflix.discovery.DiscoveryClient類的register()方法,下面是run方法的源碼

    public void run() {
        try {
            discoveryClient.refreshInstanceInfo();

            Long dirtyTimestamp = instanceInfo.isDirtyWithTime();
            if (dirtyTimestamp != null) {
                discoveryClient.register();
                instanceInfo.unsetIsDirty(dirtyTimestamp);
            }
        } catch (Throwable t) {
            logger.warn("There was a problem with the instance info replicator", t);
        } finally {
            Future next = scheduler.schedule(this, replicationIntervalSeconds, TimeUnit.SECONDS);
            scheduledPeriodicRef.set(next);
        }
    }

3.看一下DiscoveryClient.register()做了什么

?在該方法中,通過發(fā)送Rest請求進(jìn)行注冊操作,在發(fā)送請求時(shí)會傳入一個(gè)InstanceInfo,該對象就是客戶端的元數(shù)據(jù)信息。

服務(wù)獲取

?服務(wù)獲取任務(wù)也是在initScheduledTasks方法中啟動(dòng),由于客戶端需要不斷獲取服務(wù)端維護(hù)的服務(wù)實(shí)例清單,因此該任務(wù)會以定時(shí)任務(wù)啟動(dòng),在啟動(dòng)過程會首先獲取配置文件中eureka.client.registry-fetch-interval-seconds參數(shù)配置的值(默認(rèn)是30s),
然后根據(jù)配置的參數(shù)每30s(按照實(shí)際配置的值)獲取一次服務(wù)。實(shí)際獲取服務(wù)列表的時(shí)候也是發(fā)送Rest請求。

    /**
     * Initializes all scheduled tasks.
     */
    private void initScheduledTasks() {
        if (clientConfig.shouldFetchRegistry()) {
            // registry cache refresh timer
            int registryFetchIntervalSeconds = clientConfig.getRegistryFetchIntervalSeconds();
            int expBackOffBound = clientConfig.getCacheRefreshExecutorExponentialBackOffBound();
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "cacheRefresh",
                            scheduler,
                            cacheRefreshExecutor,
                            registryFetchIntervalSeconds,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new CacheRefreshThread()
                    ),
                    registryFetchIntervalSeconds, TimeUnit.SECONDS);
        }
    }
服務(wù)續(xù)約

?服務(wù)在注冊到注冊中心后,需要維持一個(gè)心跳去續(xù)約,防止被剔除,因此服務(wù)續(xù)約和服務(wù)注冊是成對存在,在同一個(gè)if條件里。首先會獲取配置文件參數(shù)中eureka.instance.lease-renewal-interval-in-seconds的值,該值默認(rèn)30s,隨后啟動(dòng)定時(shí)任務(wù),每隔30s(根據(jù)實(shí)際配置的值)向注冊中心發(fā)一次Rest請求,表明自己還活著。

    /**
     * Initializes all scheduled tasks.
     */
    private void initScheduledTasks() {

        if (clientConfig.shouldRegisterWithEureka()) {
            int renewalIntervalInSecs = instanceInfo.getLeaseInfo().getRenewalIntervalInSecs();
            int expBackOffBound = clientConfig.getHeartbeatExecutorExponentialBackOffBound();
            logger.info("Starting heartbeat executor: " + "renew interval is: {}", renewalIntervalInSecs);
            // Heartbeat timer
            scheduler.schedule(
                    new TimedSupervisorTask(
                            "heartbeat",
                            scheduler,
                            heartbeatExecutor,
                            renewalIntervalInSecs,
                            TimeUnit.SECONDS,
                            expBackOffBound,
                            new HeartbeatThread()
                    ),
                    renewalIntervalInSecs, TimeUnit.SECONDS);
        }
    }
服務(wù)注冊中心處理

?注冊中心處理Rest請求的類位于com.netflix.eureka.resources包下

?比如com.netflix.eureka.resources.ApplicationResource類中的addInstance()方法主要用來處理客戶端的注冊事件。

?注冊中心在收到客戶端發(fā)送注冊請求以后,會首先對客戶端的信息進(jìn)行校驗(yàn),校驗(yàn)過后會調(diào)用org.springframework.cloud.netflix.eureka.server.InstanceRegistry的register()方法來進(jìn)行服務(wù)注冊。

?register()方法會調(diào)用publishEvent()方法將服務(wù)注冊的事件傳播出去,緊接著調(diào)用父類com.netflix.eureka.registry.AbstractInstanceRegistry中的register()實(shí)現(xiàn),該方法會將InstanceInfo中的元數(shù)據(jù)信息保存到一個(gè)ConcurrentHashMap中。

?該HashMap有兩層數(shù)據(jù)結(jié)構(gòu),正如我們之前所說,第一層的Key存儲服務(wù)名(InstanceInfo中的appName屬性),第二層Key存儲服務(wù)實(shí)例名稱(InstanceInfo中的instanceId屬性)

配置詳解

Eureka客戶端的配置主要有以下兩個(gè)方面:

服務(wù)注冊相關(guān)的配置信息,包括注冊中心的地址、服務(wù)獲取的時(shí)間間隔、可用區(qū)域(Zone)等;

服務(wù)實(shí)例相關(guān)的配置信息,包括服務(wù)實(shí)例的名稱、IP地址、端口號、健康檢查路徑等。

?客戶端的配置類可以參考o(jì)rg.springframework.cloud.netflix.eureka.EurekaClientConfigBean

?服務(wù)端的配置類可以參考o(jì)rg.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean

服務(wù)注冊相關(guān)的配置

?這些配置信息都以eureka.client作為前綴

指定注冊中心

?指定注冊中心主要靠eureka.client.serviceUrl參數(shù),該參數(shù)的配置值值存儲在HashMap中,并且會有一組默認(rèn)值,默認(rèn)值的Key是defaultZone,value為http://localhost:8761/eureka/。

?當(dāng)構(gòu)建了高可用的服務(wù)注冊中心集群時(shí),參數(shù)的value可以配置多個(gè)注冊中心(通過,分隔)。

?為了注冊中心的安全考慮,需要為服務(wù)注冊中心加入安全校驗(yàn)。因此客戶端在配置注冊中心serviceUrl中時(shí)需要加入相應(yīng)的安全校驗(yàn)信息。比如http://:@localhost:9001/eureka/,其中username為用戶名,password為密碼。

其他配置
參數(shù)名 說明 默認(rèn)值
enabled 啟用Eureka客戶端 true
registryFetchIntervalSeconds 從服務(wù)注冊中心獲取注冊信息(服務(wù)實(shí)例清單)的間隔時(shí)間,單位s 30
instanceInfoReplicationIntervalSeconds 更新實(shí)例信息的變化到Eureka服務(wù)端的間隔時(shí)間,單位s 30
initialInstanceInfoReplicationIntervalSeconds 最初更新實(shí)例信息到Eureka服務(wù)端的間隔時(shí)間,單位s 40
eurekaServiceUrlPollIntervalSeconds 輪詢Eureka服務(wù)端地址更改的間隔時(shí)間,單位s。當(dāng)我們與Spring Cloud Config配合,動(dòng)態(tài)刷新Eureka的serviceUrl地址時(shí)需要關(guān)注該參數(shù) 300
eurekaServerReadTimeoutSeconds 讀取注冊中心信息的超時(shí)時(shí)間,單位s 8
eurekaServerConnectTimeoutSeconds 連接注冊中心的超時(shí)時(shí)間,單位s 5
eurekaServerTotalConnections 從Eureka客戶端到所有Eureka服務(wù)端的連接總數(shù) 200
eurekaServerTotalConnectionsPerHost 從Eureka客戶端到每個(gè)Eureka服務(wù)端主機(jī)的連接總數(shù) 50
eurekaConnectionIdleTimeoutSeconds Eureka服務(wù)端連接的空閑關(guān)閉時(shí)間 30
heartbeatExecutorThreadPoolSize 心跳連接池的初始化線程數(shù) 2
heartbeatExecutorExponentialBackOffBound 心跳超時(shí)重試延遲時(shí)間的最大乘數(shù)值 10
cacheRefreshExecutorThreadPoolSize 緩存刷新線程池的初始化線程池?cái)?shù) 2
cacheRefreshExecutorExponentialBackOffBound 緩存刷新重試延遲時(shí)間的最大乘數(shù)值 10
useDnsForFetchingServiceUrls 使用DNS來獲取Eureka服務(wù)端的serviceUrl false
registerWithEureka 是否要將自身的實(shí)例信息注冊到Eureka服務(wù)端 true
preferSameZoneEureka 是否偏好使用處于相同Zone的Eureka服務(wù)端 true
filterOnlyUpInstances 獲取實(shí)例時(shí)是否過濾,僅保留UP狀態(tài)的實(shí)例 true
fetchRegistry 是否從Eureka服務(wù)端獲取注冊信息 true
服務(wù)實(shí)例類配置

?該配置可以參考o(jì)rg.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean類,這些配置都以eureka.instance開頭

元數(shù)據(jù)

?在EurekaInstanceConfigBean類中有一大部分內(nèi)容是對服務(wù)實(shí)例元數(shù)據(jù)的配置,它是Eureka客戶端在向注冊中心發(fā)送注冊請求時(shí),用來描述自身服務(wù)信息的對象。

?在使用Spring Cloud Eureka時(shí),所有的配置信息都是通過EurekaInstanceConfigBean對象進(jìn)行加載,但真正進(jìn)行服務(wù)注冊的時(shí)候,會包裝成com.netflix.appinfo.InstanceInfo對象發(fā)送給Eureka服務(wù)端。

?在InstanceInfo類中,Map metadata屬性是自定義的元數(shù)據(jù)信息,其他的屬性都是標(biāo)準(zhǔn)的元數(shù)據(jù)信息。

?在配置文件可以通過eureka.instance.=的格式對標(biāo)準(zhǔn)化元數(shù)據(jù)直接進(jìn)行配置,對于自定義元數(shù)據(jù),可以通過eureka.instance.metedataMap.=的格式進(jìn)行配置。

實(shí)例名配置

?實(shí)例名,即InstanceInfo中的instanceId,它是區(qū)別同一服務(wù)中不同實(shí)例的唯一標(biāo)識。

?在原生的Netflix Eureka中,實(shí)例名稱采用主機(jī)名作為默認(rèn)值,這樣的弊端就是無法在同一主機(jī)上啟動(dòng)多個(gè)相同的服務(wù)實(shí)例。

?在Spring Cloud Eureka中,對實(shí)例名的默認(rèn)值做了更合理的擴(kuò)展,它采用了${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}

?實(shí)例名的命名規(guī)則,可以通過eureka.instance.instance-id進(jìn)行配置,比如在客戶端進(jìn)行負(fù)載均衡調(diào)用時(shí),需要啟動(dòng)多個(gè)端口進(jìn)行調(diào)試,此時(shí)就可以修改eureka.instance.instance-id=${spring.application.name}:${random.int}

端點(diǎn)配置

?在InstanceInfo中,可以看到一些URL的配置信息,如:homePageUrl、statusPageUrl、healthCheckUrl等,它分別代表了應(yīng)用主頁的URL、狀態(tài)頁的URL、健康檢查的URL。

?狀態(tài)頁和健康檢查的URL默認(rèn)使用了spring-boot-actuator模塊提供的/actuator/info和/actuator/health端點(diǎn)(2.0版本之前不帶/actuator前綴)。

?為了服務(wù)的正常運(yùn)作,必須確保/actuator/health端點(diǎn)是一個(gè)能夠被注冊中心可以訪問的地址,否則注冊中心不會根據(jù)應(yīng)用的健康檢查來更新狀態(tài)(只有eureka.client.healthcheck.enabled=true時(shí)才會以該端點(diǎn)對服務(wù)進(jìn)行健康監(jiān)測,否則會以客戶端心跳的方式。)。

?/info端點(diǎn)如果不正確,會導(dǎo)致在注冊中心點(diǎn)擊服務(wù)實(shí)例鏈接,會無法獲取到服務(wù)實(shí)例提供的信息接口。

?在大多數(shù)情況下,并不需要修改URL的配置,但是不排除特殊情況需要對這些URL做配置。比如:為應(yīng)用設(shè)置context-path,這時(shí),所有spring-boot-actuator模塊的監(jiān)控端點(diǎn)都會增加一個(gè)前綴。示例配置如下:

server.servlet.context-path=/produce

eureka.instance.status-page-url-path=${server.servlet.context-path}/info

eureka.instance.health-check-url-path=${server.servlet.context-path}/health

?eureka.instance.status-page-url-path和eureka.instance.health-check-url-path兩個(gè)參數(shù)均使用相對路徑來配置。

?eureka.instance.status-page-url和eureka.instance.health-check-url兩個(gè)配置參數(shù)使用絕對路徑進(jìn)行配置。對比上面可以發(fā)現(xiàn),如果使用相對路徑后面參數(shù)后綴都會跟著path

健康檢測

?默認(rèn)情況下,Eureka中各個(gè)服務(wù)實(shí)例的健康檢測并不是通過spring-cloud-actuator模塊的/actuator/health節(jié)點(diǎn),而是依靠客戶端的心跳來保持服務(wù)的存活。

?默認(rèn)的客戶端心跳方式無法保證客戶端提供正常的服務(wù)。比如微服務(wù)一般會有依賴的外部資源(如數(shù)據(jù)庫、緩存、消息代理等),假如與這些外部資源無法聯(lián)通,但是客戶端心跳依舊存在,這就會導(dǎo)致調(diào)用出現(xiàn)問題。

?使用spring-boot-actuator模塊的/actuator/health端點(diǎn),只需要兩部曲:

在pom.xml文件中引入spring-boot-actuator依賴

在配置文件中加入eureka.client.healthcheck.enabled=true

其他配置
參數(shù) 說明 默認(rèn)值
preferIpAddress 是否優(yōu)先以使用IP地址作為主機(jī)名的標(biāo)識 false
leaseRenewalIntervalInSeconds 客戶端向注冊中心發(fā)送心跳的間隔時(shí)間,單位s 30
leaseExpirationDurationInSeconds 服務(wù)端在收到最后一次心跳后的等待時(shí)間上限,單位s。超過該時(shí)間會對服務(wù)進(jìn)行剔除。 90
nonSecurePort 非安全的通信端口號 80
securePort 安全的通信端口號 443
nonSecurePortEnabled 是否啟用非安全的通信端口號 true
securePortEnabled 是否啟用安全的通信端口號 true
appname 服務(wù)名,默認(rèn)會取spring.application.name的值 unknown
hostname 主機(jī)名 根據(jù)計(jì)算操作系統(tǒng)的主機(jī)名進(jìn)行取值
代碼地址

spring-cloud-eureka代碼

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/76494.html

相關(guān)文章

  • SpringCloud核心教程 | 第三篇:服務(wù)注冊與發(fā)現(xiàn) Eureka篇

    摘要:下一篇介紹基于的服務(wù)注冊與調(diào)用。服務(wù)提供者工程配置這里服務(wù)提供者是使用之前進(jìn)階教程第三篇整合連接池以及監(jiān)控改造而來,這里一樣的部分就不再重復(fù)說明,下面將說明新增的部分。 Spring Cloud簡介 Spring Cloud是一個(gè)基于Spring Boot實(shí)現(xiàn)的云應(yīng)用開發(fā)工具,它為基于JVM的云應(yīng)用開發(fā)中涉及的配置管理、服務(wù)發(fā)現(xiàn)、斷路器、智能路由、微代理、控制總線、全局鎖、決策競選、分...

    scq000 評論0 收藏0
  • 一起學(xué)習(xí)使用Spring Cloud Netflix之Eureka

    摘要:筆者也是初學(xué)者,本文從創(chuàng)建項(xiàng)目工程開始,一步一步開始講解如何創(chuàng)建服務(wù)端和客戶端,一起學(xué)習(xí),共同進(jìn)步。下面我們使用工具創(chuàng)建相關(guān)項(xiàng)目。配置其中兩個(gè)屬性表明這個(gè)應(yīng)用是端,而不是端。至此,端和端已經(jīng)部署成功。 前言 spring cloud為互聯(lián)企業(yè)構(gòu)建微服務(wù)提供了一整套的技術(shù)組件,其中Eureka是Spring Cloud體系中的核心。Netfix不是一個(gè)技術(shù)概念,它原本是國外一個(gè)視頻網(wǎng)站的...

    李義 評論0 收藏0
  • SpringCloud打造微服務(wù)平臺--概覽

    摘要:授權(quán)框架使第三方應(yīng)用程序來獲取對服務(wù)的有限訪問機(jī)會。無論是通過編排資源所有者和服務(wù)之間的交互批準(zhǔn)的資源所有者,或通過允許第三方應(yīng)用程序來獲取自己的訪問權(quán)限。 SpringCloud打造微服務(wù)平臺--概覽 簡述 SpringCloud是什么 Spring Boot和SpringCloud是什么關(guān)系 Spring Boot是Spring的一套快速WEB開發(fā)的腳手架,可建立獨(dú)立的Sprin...

    siberiawolf 評論0 收藏0
  • 一起學(xué)習(xí)使用Spring Cloud Netflix之Ribbon

    摘要:本例中介紹如何使用來完成服務(wù)調(diào)用并實(shí)現(xiàn)負(fù)載均衡。即,對于注冊中心而言,生產(chǎn)者和調(diào)用者都是端。文件配置如下在文件中,我們將應(yīng)用命名為,端口為,表示注冊中心地址。 前言 Ribbon是Spring Cloud體系中完成負(fù)載均衡的重要組件。Spring Cloud體系中有兩種完成服務(wù)調(diào)用的組件,一種是Ribbon+RestTemplate,另一種Feign。Feign默認(rèn)使用的也是Ribbo...

    nidaye 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<