隨着微服務應用的不斷增長,靜態配置會愈來愈難以維護,而且隨着業務的不斷髮展,集羣規模、服務位置、服務命名都會發生變化,手動維護的方式極易發生錯誤或是命名衝突問題。所以須要服務治理框架對微服務實例進行管理,服務治理是微服務架構中最核心的功能和模塊,主要用來各個微服務實例的自動化註冊和發現。java
在服務治理框架中,一般都會有一個服務註冊中心。git
每個微服務實例向註冊中心登記本身提供的服務,將主機、端口號、版本號、通訊協議等一些信息告知註冊中心。web
註冊中心按服務名分類組織服務清單。spring
服務註冊中心須要以心跳的方式監測服務清單中的服務是否可用,若是不可用,須要將不可用的服務實例進行剔除。shell
服務間的調用經過向服務名發起請求調用實現。 服務調用方在調用提供方的接口時,並不知道提供方的具體地址。數據庫
服務調用方須要從註冊中心獲取全部服務的實例清單,才能夠實現對具體服務實例的訪問。緩存
服務調用方在發起調用時,會以某種策略取出一個具體的服務實例進行服務調用(客戶端負載均衡)。安全
在實際的環境中,爲了提供性能,並不會採用每次都向服務註冊中心獲取服務的方式進行服務的調用,而且不一樣的應用場景在緩存和服務剔除等機制上能夠採用不一樣的實現策略。網絡
Spring Cloud Eureka採用Netflix Eureka來實現服務註冊與發現,包含客戶端和服務端組件。數據結構
支持高可用配置。
依託於強一致性提供良好的服務實例可用性。
服務註冊中心之間能夠經過異步模式互相複製各自的狀態。
主要用於服務的註冊和發現。
客戶端能夠經過註解和參數配置的方式實現註冊與發現。
Eureka客戶端向註冊中心註冊自身提供的服務並週期性地發送心跳來更新它的服務租約。
Eureka客戶端從服務端查詢當前註冊的服務信息並把它們緩存到本地並週期性的刷新服務狀態。
package cn.sh.eureka.server; //代碼位於該包下
1.準備pom.xml
<!--導入Spring Boot Starter--> <!-- 父項目parent配置指定爲spring-boot-starter-parent的2.0.3.RELEASE版本, 該父項目中定義了Spring Boot版本的基礎依賴以及一些默認配置內容。 好比,配置文件application.properties的位置等。 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> </parent> <dependencies> <!--導入Eureka服務端(註冊中心)依賴jar包--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> <version>1.2.7.RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2.準備配置文件application.properties
#端口號 server.port=9000 eureka.instance.hostname=localhost #禁止註冊中心註冊本身 eureka.client.register-with-eureka=false #禁止註冊中心搜索服務 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 啓動一個註冊中心 */ @EnableEurekaServer @SpringBootApplication public class EurekaServer { public static void main(String[] args) { SpringApplication.run(EurekaServer.class, args); } }
1.準備pom.xml
<!--導入Spring Boot Starter--> <!-- 父項目parent配置指定爲spring-boot-starter-parent的2.0.3.RELEASE版本, 該父項目中定義了Spring Boot版本的基礎依賴以及一些默認配置內容。 好比,配置文件application.properties的位置等。 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> </parent> <dependencies> <!--增長Web支持--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--增長Eureka客戶端支持--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.2.5.RELEASE</version> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Finchley.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2.準備配置文件application.properties
#端口號 server.port=8000 #服務名稱 spring.application.name=produce-service #服務註冊中心地址 eureka.client.serviceUrl.defaultZone=http://localhost:9000/eureka/
3.編寫produce-service服務的代碼
代碼位於spring-cloud-eureka-client模塊下
package cn.sh.eureka.produce; //代碼包位置
Eureka Server的高可用實際上就是講本身做爲服務向其餘服務註冊中心註冊本身,這樣能夠造成一組互相註冊的服務註冊中心,以實現服務清單的互相同步,達到高可用的效果。
相關實如今spring-cloud-eureka-server模塊下,注意在host配置文件中配置peer1和peer2的轉換
將代碼經過maven編譯成jar包
經過java命令啓動兩個註冊中心
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
啓動以後,會發如今註冊中心peer1的面板上的available-replicas中出現http://peer2:9002/eureka/,一樣,在註冊中心peer2面板上的available-replicas中出現http://peer1:9001/eureka/
eureka.instance.prefer-ip-address=true, 使用IP地址的方式指定註冊中心的地址,默認false,以主機名定義註冊中心地址
服務消費者的主要目標是發現和消費服務。其中服務發現由Eureka客戶端完成,服務消費由Ribbon完成。
Ribbon是一個基於HTTP和TCP的客戶端負載均衡器,它能夠經過在客戶端中配置的ribbonServerList服務實例列表去輪詢訪問以達到負載均衡的做用。
Ribbon與Eureka結合使用時,ribbonServerList服務實例列表會被DiscoveryEnabledNIWSServerList重寫,擴展成從Eureka註冊中心中獲取服務列表。
Ribbon與Eureka結合使用時,採用NIWSDiscoveryPing取代IPing,它將職責委託給Eureka來肯定服務實例是否啓動。
1.pom.xml
增長對Ribbon的支持
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.2.7.RELEASE</version> </dependency>
2.相關代碼在spring-cloud-eureka-consumer模塊下
備註: 通常一個應用既是服務提供者也是服務消費者。
Eureka服務體系圖
服務提供者會以Rest請求的方式註冊到註冊中心上,在請求過程當中會攜帶自身的一些元數據信息。註冊中心在收到請求後,會將元數據信息保存到一個雙層Map結構中,外層的key是服務名稱,內層的key是具體的服務實例名稱。
eureka.client.register-with-eureka,若是該參數的值等於false,不會進行註冊。
若是兩個服務註冊在兩個不一樣的註冊中心上,兩個註冊中心互相註冊成爲服務(集羣),此時,當服務提供者向其中一個註冊中心發起請求時,該註冊中心會將請求準發給集羣中的其餘註冊中心,從而實現註冊中心之間的服務同步。
因爲服務同步的存在,服務提供者的信息能夠在任意一臺註冊中心上獲取。
在服務註冊完成以後,服務提供者須要維護一個心跳來告知註冊中心服務實例處於正常運行狀態中,防止註冊中心將正常的服務實例剔除出注冊中心。上述操做就成爲服務續約。
屬性 | 含義 |
---|---|
eureka.instance.lease-renewal-interval-in-seconds | 服務續約任務調用的間隔時間,默認時間30s |
eureka.instance.lease-expiration-duration-in-seconds | 服務失效時間(表示註冊中心至上一次收到客戶端的心跳以後,等待下一次心跳的超時時間,在這個時間內若沒收到下一次心跳,則將移除該客戶端實例),默認90s |
啓動服務消費者時,服務消費者會向註冊中心發起一個Rest請求,來獲取註冊中心維護的服務實例清單。可是爲了提升性能,註冊中心會維護一份只讀的服務清單返回給客戶端,該緩存的服務清單會每隔30s刷新一次。
eureka.client.fetch-registry,若是該參數被設置爲false,沒法向註冊中心獲取服務清單。
eureka.client.registry-fetch-interval-seconds,緩存清單的刷新時間,默認30s。
服務消費者得到服務清單後,能夠根據服務名獲取具體服務實例列表(元數據信息),根據本身的策略選擇具體的服務實例進行調用。
Eureka有Region和Zone的概念,一個Region中會有多個Zone,每一個客戶端都須要註冊到一個Zone中,因此客戶端對應一個Region和一個Zone。在服務進行調用時,優先訪問同一個Zone中的服務提供方,若訪問不到,再訪問其餘Zone。
當服務實例正常關閉時,服務實例會發送一個服務下線的Rest請求給註冊中心。註冊中心在收到請求後,會將該服務實例的狀態置爲DOWN,而且將下線時間廣播出去。
當服務實例未正常下線時(內存溢出、網絡故障),服務註冊中心未能收到服務下線的Rest請求。註冊中心在啓動時會建立一個定時任務,默認每隔一段時間(60s)將當前清單中超時(服務失效時間,默認90s)沒有續約的服務進行剔除。
註冊中心在運行期間,會統計心跳失敗比例在15分鐘內是否低於85%,若是出現低於的狀況,註冊中心會將當前服務實例的註冊信息保護起來,讓這些實例不會過時。可是,在保護期時間內,若是實例出現問題,那麼服務調用者很容易拿到該實例調用失敗,因此服務調用者必需要有容錯機制(請求重試、斷路由器等)。
eureka.server.enable-self-preservation,若是該值設置爲false,則不啓用自我保護機制,默認值爲true
分析源碼,能夠以Eureka客戶端和Eureka服務端做爲切入點。
在應用獲取服務列表和向註冊中心註冊成爲服務時只作了兩件事:
該註解的主要做用是用來開啓一個DiscoveryClient的實例。
類圖之後補充
類 | 做用 |
---|---|
org.springframework.cloud.client.discovery.DiscoveryClient | Spring Cloud的接口,定義了發現服務的經常使用抽象方法,這樣作的好處是能夠屏蔽服務治理的細節,能夠方便的切換不一樣的服務治理框架,不須要改動程序代碼,只須要添加一些針對服務治理框架的配置 |
com.netflix.appinfo.InstanceInfo.LookupService | 定義了Eureka發現服務的抽象方法 |
com.netflix.discovery.EurekaClient | 定義了Eureka發現服務的抽象方法,繼承LookupService |
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient | Spring中的DiscoveryClient接口的實現,對Eureka發現服務的封裝,實現EurekaClient接口,Eureka接口繼承LookupService接口 |
com.netflix.discovery.DiscoveryClient | 實現EurekaClient接口,真正的服務發現實現類 |
經過頭部的註釋信息,咱們能夠獲得如下信息:
1.DiscoveryClient類主要用於幫助客戶端和註冊中心互相協做。
2.Eureka客戶端主要負責的任務:
3.Eureka客戶端須要配置一個註冊中心的URL列表
關鍵類:com.netflix.discovery.endpoint.EndpointUtils
關鍵方法:Map<String, List<String>> 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<String, List<String>> getServiceUrlsMapFromConfig(EurekaClientConfig clientConfig, String instanceZone, boolean preferSameZone) { Map<String, List<String>> 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<String> 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函數,從配置文件中讀取一個Region返回,因此一個微服務應用只能屬於一個Region,若是不進行配置,默認值default,eureka.client.region該屬性能夠配置Region
經過getAvailabilityZones函數,若是沒有爲Region配置Zone,默認值是defaultZone,所以註冊中心URL列表的默認配置參數爲eureka.client.serviceUrl.defaultZone。eureka.client.availability-zone.<regionName>能夠配置Region下面的Zone,Zone的配置有多個(用,分隔)。
2.加載serviceUrls
按照必定的方法以此加載每一個Zone中的urls,存放在一個Map<String, List<String>>中。
當使用Ribbon來調用服務時,Ribbon的默認策略是優先訪問和客戶端處於同一個Zone的微服務實例。
在獲取到客戶端配置的serviceUrls以後,就能夠進行服務的註冊,詳情請看下面。
關鍵類:com.netflix.discovery.DiscoveryClient
關鍵方法:void initScheduledTasks(),DiscoveryClient的構造函數會對此方法進行調用
該方法主要用來啓用定時任務,主要包括獲取服務Task、服務註冊、服務續約(心跳),本次先着重看服務註冊的邏輯
/** * 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 該參數要設置成true,默認值爲true
若是上述參數值爲true,則執行註冊任務
2.新建InstanceInfoReplicator,利用其來進行註冊
該類實現了Runnable接口,觀察run方法,在進行註冊時實際調用的是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()作了什麼
在該方法中,經過發送Rest請求進行註冊操做,在發送請求時會傳入一個InstanceInfo,該對象就是客戶端的元數據信息。
服務獲取任務也是在initScheduledTasks方法中啓動,因爲客戶端須要不斷獲取服務端維護的服務實例清單,所以該任務會以定時任務啓動,在啓動過程會首先獲取配置文件中eureka.client.registry-fetch-interval-seconds參數配置的值(默認是30s),
而後根據配置的參數每30s(按照實際配置的值)獲取一次服務。實際獲取服務列表的時候也是發送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); } }
服務在註冊到註冊中心後,須要維持一個心跳去續約,防止被剔除,所以服務續約和服務註冊是成對存在,在同一個if條件裏。首先會獲取配置文件參數中eureka.instance.lease-renewal-interval-in-seconds的值,該值默認30s,隨後啓動定時任務,每隔30s(根據實際配置的值)向註冊中心發一次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); } }
註冊中心處理Rest請求的類位於com.netflix.eureka.resources包下
好比com.netflix.eureka.resources.ApplicationResource類中的addInstance()方法主要用來處理客戶端的註冊事件。
註冊中心在收到客戶端發送註冊請求之後,會首先對客戶端的信息進行校驗,校驗事後會調用org.springframework.cloud.netflix.eureka.server.InstanceRegistry的register()方法來進行服務註冊。
register()方法會調用publishEvent()方法將服務註冊的事件傳播出去,緊接着調用父類com.netflix.eureka.registry.AbstractInstanceRegistry中的register()實現,該方法會將InstanceInfo中的元數據信息保存到一個ConcurrentHashMap中。
該HashMap有兩層數據結構,正如咱們以前所說,第一層的Key存儲服務名(InstanceInfo中的appName屬性),第二層Key存儲服務實例名稱(InstanceInfo中的instanceId屬性)
Eureka客戶端的配置主要有如下兩個方面:
客戶端的配置類能夠參考org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
服務端的配置類能夠參考org.springframework.cloud.netflix.eureka.server.EurekaServerConfigBean
這些配置信息都以eureka.client做爲前綴
指定註冊中心主要靠eureka.client.serviceUrl參數,該參數的配置值值存儲在HashMap中,而且會有一組默認值,默認值的Key是defaultZone,value爲http://localhost:8761/eureka/。
當構建了高可用的服務註冊中心集羣時,參數的value能夠配置多個註冊中心(經過,分隔)。
爲了註冊中心的安全考慮,須要爲服務註冊中心加入安全校驗。所以客戶端在配置註冊中心serviceUrl中時須要加入相應的安全校驗信息。好比http://<username>:<password>@localhost:9001/eureka/,其中username爲用戶名,password爲密碼。
參數名 | 說明 | 默認值 |
---|---|---|
enabled | 啓用Eureka客戶端 | true |
registryFetchIntervalSeconds | 從服務註冊中心獲取註冊信息(服務實例清單)的間隔時間,單位s | 30 |
instanceInfoReplicationIntervalSeconds | 更新實例信息的變化到Eureka服務端的間隔時間,單位s | 30 |
initialInstanceInfoReplicationIntervalSeconds | 最初更新實例信息到Eureka服務端的間隔時間,單位s | 40 |
eurekaServiceUrlPollIntervalSeconds | 輪詢Eureka服務端地址更改的間隔時間,單位s。當咱們與Spring Cloud Config配合,動態刷新Eureka的serviceUrl地址時須要關注該參數 | 300 |
eurekaServerReadTimeoutSeconds | 讀取註冊中心信息的超時時間,單位s | 8 |
eurekaServerConnectTimeoutSeconds | 鏈接註冊中心的超時時間,單位s | 5 |
eurekaServerTotalConnections | 從Eureka客戶端到全部Eureka服務端的鏈接總數 | 200 |
eurekaServerTotalConnectionsPerHost | 從Eureka客戶端到每一個Eureka服務端主機的鏈接總數 | 50 |
eurekaConnectionIdleTimeoutSeconds | Eureka服務端鏈接的空閒關閉時間 | 30 |
heartbeatExecutorThreadPoolSize | 心跳鏈接池的初始化線程數 | 2 |
heartbeatExecutorExponentialBackOffBound | 心跳超時重試延遲時間的最大乘數值 | 10 |
cacheRefreshExecutorThreadPoolSize | 緩存刷新線程池的初始化線程池數 | 2 |
cacheRefreshExecutorExponentialBackOffBound | 緩存刷新重試延遲時間的最大乘數值 | 10 |
useDnsForFetchingServiceUrls | 使用DNS來獲取Eureka服務端的serviceUrl | false |
registerWithEureka | 是否要將自身的實例信息註冊到Eureka服務端 | true |
preferSameZoneEureka | 是否偏好使用處於相同Zone的Eureka服務端 | true |
filterOnlyUpInstances | 獲取實例時是否過濾,僅保留UP狀態的實例 | true |
fetchRegistry | 是否從Eureka服務端獲取註冊信息 | true |
該配置能夠參考org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean類,這些配置都以eureka.instance開頭
在EurekaInstanceConfigBean類中有一大部份內容是對服務實例元數據的配置,它是Eureka客戶端在向註冊中心發送註冊請求時,用來描述自身服務信息的對象。
在使用Spring Cloud Eureka時,全部的配置信息都是經過EurekaInstanceConfigBean對象進行加載,但真正進行服務註冊的時候,會包裝成com.netflix.appinfo.InstanceInfo對象發送給Eureka服務端。
在InstanceInfo類中,Map<String, String> metadata屬性是自定義的元數據信息,其餘的屬性都是標準的元數據信息。
在配置文件能夠經過eureka.instance.<properties>=<value>的格式對標準化元數據直接進行配置,對於自定義元數據,能夠經過eureka.instance.metedataMap.<key>=<value>的格式進行配置。
實例名,即InstanceInfo中的instanceId,它是區別同一服務中不一樣實例的惟一標識。
在原生的Netflix Eureka中,實例名稱採用主機名做爲默認值,這樣的弊端就是沒法在同一主機上啓動多個相同的服務實例。
在Spring Cloud Eureka中,對實例名的默認值作了更合理的擴展,它採用了${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}
實例名的命名規則,能夠經過eureka.instance.instance-id進行配置,好比在客戶端進行負載均衡調用時,須要啓動多個端口進行調試,此時就能夠修改eureka.instance.instance-id=${spring.application.name}:${random.int}
在InstanceInfo中,能夠看到一些URL的配置信息,如:homePageUrl、statusPageUrl、healthCheckUrl等,它分別表明了應用主頁的URL、狀態頁的URL、健康檢查的URL。
狀態頁和健康檢查的URL默認使用了spring-boot-actuator模塊提供的/actuator/info和/actuator/health端點(2.0版本以前不帶/actuator前綴)。
爲了服務的正常運做,必須確保/actuator/health端點是一個可以被註冊中心能夠訪問的地址,不然註冊中心不會根據應用的健康檢查來更新狀態(只有eureka.client.healthcheck.enabled=true時纔會以該端點對服務進行健康監測,不然會以客戶端心跳的方式。)。
/info端點若是不正確,會致使在註冊中心點擊服務實例連接,會沒法獲取到服務實例提供的信息接口。
在大多數狀況下,並不須要修改URL的配置,可是不排除特殊狀況須要對這些URL作配置。好比:爲應用設置context-path,這時,全部spring-boot-actuator模塊的監控端點都會增長一個前綴。示例配置以下:
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兩個參數均使用相對路徑來配置。
eureka.instance.status-page-url和eureka.instance.health-check-url兩個配置參數使用絕對路徑進行配置。對比上面能夠發現,若是使用相對路徑後面參數後綴都會跟着path
默認狀況下,Eureka中各個服務實例的健康檢測並非經過spring-cloud-actuator模塊的/actuator/health節點,而是依靠客戶端的心跳來保持服務的存活。
默認的客戶端心跳方式沒法保證客戶端提供正常的服務。好比微服務通常會有依賴的外部資源(如數據庫、緩存、消息代理等),假如與這些外部資源沒法聯通,可是客戶端心跳依舊存在,這就會致使調用出現問題。
使用spring-boot-actuator模塊的/actuator/health端點,只須要兩部曲:
參數 | 說明 | 默認值 |
---|---|---|
preferIpAddress | 是否優先以使用IP地址做爲主機名的標識 | false |
leaseRenewalIntervalInSeconds | 客戶端向註冊中心發送心跳的間隔時間,單位s | 30 |
leaseExpirationDurationInSeconds | 服務端在收到最後一次心跳後的等待時間上限,單位s。超過該時間會對服務進行剔除。 | 90 |
nonSecurePort | 非安全的通訊端口號 | 80 |
securePort | 安全的通訊端口號 443 | |
nonSecurePortEnabled | 是否啓用非安全的通訊端口號 | true |
securePortEnabled | 是否啓用安全的通訊端口號 | true |
appname | 服務名,默認會取spring.application.name的值 | unknown |
hostname | 主機名 | 根據計算操做系統的主機名進行取值 |