Eureka服務注冊與發(fā)現(xiàn)
創(chuàng)建服務注冊中心
- 添加pom依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 啟動一個服務注冊中心猖闪,只需要一個注解@EnableEurekaServer,這個注解需要在springboot工程的啟動application類上加
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run( EurekaServerApplication.class, args );
}
}
- 默認情況下erureka server也是一個eureka client ,必須要指定一個 server,eureka server的配置文件如下
server.port=8761
eureka.instance.hostname=localhost
#防止自己注冊自己
eureka.client.register-with-eureka=false
#注冊中心的職責就是維護服務實例,它并不需要去檢索服務,所以設置成false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/
-
啟動Eureka-server,查看UI界面
創(chuàng)建服務提供者
- 添加pom依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 通過注解@EnableEurekaClient 表明自己是一個eurekaclient.
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceHiApplication.class, args );
}
}
- 配置文件配置
server.port=8762
#為服務命名
spring.application.name=eureka-client
#指定服務注冊中心地址
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
-
啟動服務
啟動服務天通,如果控制臺輸入如下的日志,說明服務注冊成功
并且此時再去查看服務注冊中心熄驼,會發(fā)現(xiàn)會有一個服務實力已注冊到注冊中心
- 源碼分析
使用@EnableEurekaClient注解或者@EnableDiscoveryClient注解都可以完成服務的注冊,我們可以先看下@EnableEurekaClient的源碼,
/**
* Convenience annotation for clients to enable Eureka discovery configuration
* (specifically). Use this (optionally) in case you want discovery and know for sure that
* it is Eureka you want. All it does is turn on discovery and let the autoconfiguration
* find the eureka classes if they are available (i.e. you need Eureka on the classpath as
* well).
*
* @author Dave Syer
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface EnableEurekaClient {
}
什么多余的注解都沒有像寒,只能看到這是一個簡單的注解標識,我們可以看一下注釋:
/**
* Convenience annotation for clients to enable Eureka discovery configuration
* (specifically). Use this (optionally) in case you want discovery and know for sure that
* it is Eureka you want. All it does is turn on discovery and let the autoconfiguration
* find the eureka classes if they are available (i.e. you need Eureka on the classpath as
* well).
*
* @author Dave Syer
* @author Spencer Gibb
*/
簡單的翻譯一下:
為客戶端提供方便的注釋瓜贾,以啟用Eureka發(fā)現(xiàn)配置(特別是)诺祸。使用這個(可選),如果你想要發(fā)現(xiàn)祭芦,
并確定它是你想要的Eureka筷笨。它所做的一切就是打開發(fā)現(xiàn),并讓自動配置在可用的情況下找到eureka類(即龟劲,您也需要類路徑上的Eureka)胃夏。
閱讀上面的注釋,我們很清楚的知道昌跌,其實@EnableEurekaClient注解就是一種方便使用eureka的注解而已仰禀,可以說使用其他的注冊中心后,都可以使用@EnableDiscoveryClient注解蚕愤,但是使用@EnableEurekaClient的情景答恶,就是在服務采用eureka作為注冊中心的時候,使用場景較為單一萍诱。
我們在看一下EnableDiscoveryClient的源碼:
/**
* Annotation to enable a DiscoveryClient implementation.
* 注釋以啟用DiscoveryClient實現(xiàn)悬嗓。
* @author Spencer Gibb
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(EnableDiscoveryClientImportSelector.class)
public @interface EnableDiscoveryClient {
/**
* If true, the ServiceRegistry will automatically register the local server.
*/
boolean autoRegister() default true;
}
從該注解的注釋中我們知道,它主要用來開啟DiscoveryClient的實力砂沛。查看DiscoveryClient相關源碼梳理得到如下圖所示的關系:
右邊的org.springframework.cloud.client.discovery.DiscoveryClient是SpringCloud的接口烫扼,它定義了用來發(fā)現(xiàn)服務的常用方法曙求,通過該接口有效的屏蔽服務治理的實現(xiàn)細節(jié)碍庵,所以使用SpringCloud構建的微服務應用可以很方便的切換不同的服務治理框架映企,而不改動程序代碼,只需要添加一些針對服務治理框架的配置即可静浴。如堰氓,該接口的實現(xiàn)類有如下幾種,我們使用了其中的一種苹享。
我們看一看com.netflix.discovery.DiscoveryClient類的注解:
該類的核心功能就是完成向Eureka Server服務中心的注冊焚挠,續(xù)約,當服務shutdown的時候取消租約漓骚,查詢注冊到Eureka Server的服務實例列表蝌衔。
- 服務注冊
我們可以看到帶有@Inject注解的DiscoverClient的構造函數(shù)
@Inject
DiscoveryClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs args,
Provider<BackupRegistry> backupRegistryProvider) {
......
......
try {
// default size of 2 - 1 each for heartbeat and cacheRefresh
scheduler = Executors.newScheduledThreadPool(2,
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-%d")
.setDaemon(true)
.build());
heartbeatExecutor = new ThreadPoolExecutor(
1, clientConfig.getHeartbeatExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-HeartbeatExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
cacheRefreshExecutor = new ThreadPoolExecutor(
1, clientConfig.getCacheRefreshExecutorThreadPoolSize(), 0, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
new ThreadFactoryBuilder()
.setNameFormat("DiscoveryClient-CacheRefreshExecutor-%d")
.setDaemon(true)
.build()
); // use direct handoff
} catch (Throwable e) {
throw new RuntimeException("Failed to initialize DiscoveryClient!", e);
}
if (clientConfig.shouldRegisterWithEureka() && clientConfig.shouldEnforceRegistrationAtInit()) {
try {
if (!register() ) {
throw new IllegalStateException("Registration error at startup. Invalid server response.");
}
} catch (Throwable th) {
logger.error("Registration error at startup: {}", th.getMessage());
throw new IllegalStateException(th);
}
}
// finally, init the schedule tasks (e.g. cluster resolvers, heartbeat, instanceInfo replicator, fetch
initScheduledTasks();
......
......
initTimestampMs = System.currentTimeMillis();
logger.info("Discovery Client initialized at timestamp {} with initial instances count: {}",
initTimestampMs, this.getApplications().size());
}
可以看到 initScheduledTasks()方法,我們在具體看initScheduledTasks()方法
/**
* 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);
// InstanceInfo replicator
instanceInfoReplicator = new InstanceInfoReplicator(
this,
instanceInfo,
clientConfig.getInstanceInfoReplicationIntervalSeconds(),
2); // burstSize
......
......
instanceInfoReplicator.start(clientConfig.getInitialInstanceInfoReplicationIntervalSeconds());
} else {
logger.info("Not registering with Eureka server per configuration");
}
}
"服務續(xù)約"蝌蹂,"服務注冊"在同一個if語句中噩斟,服務注冊到Eureka Server后,需要有一個心跳去續(xù)約孤个,表明自己還活著剃允,可用,防止被剔除齐鲤。對于服務續(xù)約相關的時間控制參數(shù):
#指示eureka客戶端需要向eureka服務器發(fā)送心跳的頻率(以秒為單位)硅急,以指示該服務器仍處于活動狀態(tài)
eureka.instance.lease-renewal-interval-in-seconds=30
#指示eureka服務器在接收到最后一個心跳之后等待的時間(以秒為單位),然后才可以從視圖中刪除該實例佳遂,
eureka.instance.lease-expiration-duration-in-seconds=90
可以繼續(xù)查看InstanceInfoReplicator的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);
}
}
可以看到discoveryClient.register()完成了服務的注冊功能营袜。繼續(xù)查看register()的方法
/**
* Register with the eureka service by making the appropriate REST call.
*/
boolean register() throws Throwable {
logger.info(PREFIX + "{}: registering service...", appPathIdentifier);
EurekaHttpResponse<Void> httpResponse;
try {
httpResponse = eurekaTransport.registrationClient.register(instanceInfo);
} catch (Exception e) {
logger.warn(PREFIX + "{} - registration failed {}", appPathIdentifier, e.getMessage(), e);
throw e;
}
if (logger.isInfoEnabled()) {
logger.info(PREFIX + "{} - registration status: {}", appPathIdentifier, httpResponse.getStatusCode());
}
return httpResponse.getStatusCode() == 204;
}
可以看到注冊的時候傳入了instanceInfo對象,我們可以看看instanceInfo對象
public class InstanceInfo {
private static final String VERSION_UNKNOWN = "unknown";
/**
* {@link InstanceInfo} JSON and XML format for port information does not follow the usual conventions, which
* makes its mapping complicated. This class represents the wire format for port information.
*/
public static class PortWrapper {
private final boolean enabled;
private final int port;
@JsonCreator
public PortWrapper(@JsonProperty("@enabled") boolean enabled, @JsonProperty("$") int port) {
this.enabled = enabled;
this.port = port;
}
public boolean isEnabled() {
return enabled;
}
public int getPort() {
return port;
}
}
private static final Logger logger = LoggerFactory.getLogger(InstanceInfo.class);
public static final int DEFAULT_PORT = 7001;
public static final int DEFAULT_SECURE_PORT = 7002;
public static final int DEFAULT_COUNTRY_ID = 1; // US
// The (fixed) instanceId for this instanceInfo. This should be unique within the scope of the appName.
private volatile String instanceId;
private volatile String appName;
@Auto
private volatile String appGroupName;
private volatile String ipAddr;
private static final String SID_DEFAULT = "na";
@Deprecated
private volatile String sid = SID_DEFAULT;
private volatile int port = DEFAULT_PORT;
private volatile int securePort = DEFAULT_SECURE_PORT;
@Auto
private volatile String homePageUrl;
@Auto
private volatile String statusPageUrl;
@Auto
private volatile String healthCheckUrl;
@Auto
private volatile String secureHealthCheckUrl;
@Auto
private volatile String vipAddress;
@Auto
private volatile String secureVipAddress;
@XStreamOmitField
private String statusPageRelativeUrl;
@XStreamOmitField
private String statusPageExplicitUrl;
@XStreamOmitField
private String healthCheckRelativeUrl;
@XStreamOmitField
private String healthCheckSecureExplicitUrl;
@XStreamOmitField
private String vipAddressUnresolved;
@XStreamOmitField
private String secureVipAddressUnresolved;
@XStreamOmitField
private String healthCheckExplicitUrl;
@Deprecated
private volatile int countryId = DEFAULT_COUNTRY_ID; // Defaults to US
private volatile boolean isSecurePortEnabled = false;
private volatile boolean isUnsecurePortEnabled = true;
private volatile DataCenterInfo dataCenterInfo;
private volatile String hostName;
private volatile InstanceStatus status = InstanceStatus.UP;
private volatile InstanceStatus overriddenStatus = InstanceStatus.UNKNOWN;
@XStreamOmitField
private volatile boolean isInstanceInfoDirty = false;
private volatile LeaseInfo leaseInfo;
@Auto
private volatile Boolean isCoordinatingDiscoveryServer = Boolean.FALSE;
@XStreamAlias("metadata")
private volatile Map<String, String> metadata;
@Auto
private volatile Long lastUpdatedTimestamp;
@Auto
private volatile Long lastDirtyTimestamp;
@Auto
private volatile ActionType actionType;
@Auto
private volatile String asgName;
private String version = VERSION_UNKNOWN;
我們可以看到注冊服務的信息包括port、instanceId丑罪、appName荚板、ipAddr、homePageUrl吩屹、vipAddress......等等跪另,該對象就是注冊時客戶端發(fā)送給服務端的元數(shù)據(jù)。
- 服務獲取與服務續(xù)約
我們可以繼續(xù)查看DiscoveryClient類的initScheduledTasks()方法
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);
}
......
......
}
默認情況下煤搜,eureka.client.fetch-registry=true,大部分情況下免绿,我們不需要關心。為了定期更新服務端的服務清單擦盾,以保證客戶端能夠能夠訪問確實健康的服務實例嘲驾,服務獲取的請求不會只限于服務啟動淌哟,而是一個定時執(zhí)行的任務,eureka.client.registry-fetch-interval-seconds=30辽故,默認值是30s徒仓,意思是從eureka獲取注冊表信息的頻率(秒)是30秒。我們繼續(xù)查看源碼如下:
/**
* The heartbeat task that renews the lease in the given intervals.
*/
private class HeartbeatThread implements Runnable {
public void run() {
if (renew()) {
lastSuccessfulHeartbeatTimestamp = System.currentTimeMillis();
}
}
}
繼續(xù)查看renew()方法,可以看到續(xù)約方式是 通過合適的rest方式調(diào)用完成與eureka service的續(xù)約誊垢。
發(fā)送的信息也很簡單掉弛,只需要三個參數(shù):
instanceInfo.getAppName()
:name of the application registering with discovery.
instanceInfo.getId()
:the unique id of the instance
instanceInfo
:The class that holds information required for registration with Eureka Server and to be discovered by other components.
/**
* Renew with the eureka service by making the appropriate REST call
*/
boolean renew() {
EurekaHttpResponse<InstanceInfo> httpResponse;
try {
httpResponse = eurekaTransport.registrationClient.sendHeartBeat(instanceInfo.getAppName(), instanceInfo.getId(), instanceInfo, null);
logger.debug(PREFIX + "{} - Heartbeat status: {}", appPathIdentifier, httpResponse.getStatusCode());
if (httpResponse.getStatusCode() == 404) {
REREGISTER_COUNTER.increment();
logger.info(PREFIX + "{} - Re-registering apps/{}", appPathIdentifier, instanceInfo.getAppName());
long timestamp = instanceInfo.setIsDirtyWithTime();
boolean success = register();
if (success) {
instanceInfo.unsetIsDirty(timestamp);
}
return success;
}
return httpResponse.getStatusCode() == 200;
} catch (Throwable e) {
logger.error(PREFIX + "{} - was unable to send heartbeat!", appPathIdentifier, e);
return false;
}
}
- 服務注冊中心
下面我們來看服務注冊中心如何處理各類客戶端的Rest請求的。Eureka Server對于各類REST請求的定義都位于com.netflix.eureka.resources
包下喂走,我們查看一下com.netflix.eureka.registry.AbstractInstanceRegistry
的register()
方法
/**
* Registers a new instance with a given duration.
*
* @see com.netflix.eureka.lease.LeaseManager#register(java.lang.Object, int, boolean)
*/
public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) {
...
read.lock();
Map<String, Lease<InstanceInfo>> gMap = registry.get(registrant.getAppName());
REGISTER.increment(isReplication);
if (gMap == null) {
final ConcurrentHashMap<String, Lease<InstanceInfo>> gNewMap = new ConcurrentHashMap<String, Lease<InstanceInfo>>();
gMap = registry.putIfAbsent(registrant.getAppName(), gNewMap);
if (gMap == null) {
gMap = gNewMap;
}
}
......
}
我們可以看到服務注冊的信息被存儲在了registry對象中殃饿,該對象是ConcurrentHashMap<String, Map<String, Lease<InstanceInfo>>>
,注冊中心存儲了兩層Map結構芋肠,第一層的key存儲服務名:InstanceInfo中的appName屬性壁晒,第二層的key存儲實例名:InstanceInfo中的instanceId屬性。
配置詳解
在Eureka的服務治理體系中业栅,主要分為客戶端和服務端兩個不同的角色秒咐,服務端為服務注冊中心,而客戶端為各個提供接口的微服務應用碘裕。
Eureka客戶端的配置主要分為以下兩個方面:
- 服務注冊相關的配置信息携取,包括服務注冊中心的地址、服務獲取的時間間隔帮孔、可用區(qū)域等
- 服務實例相關的配置信息雷滋,包括服務實例的名稱、IP地址文兢、端口號晤斩、健康檢查路徑等。
Eureka Server的配置均已eureka.server作為前綴姆坚。
服務注冊類配置
服務注冊類的配置信息澳泵,可用查看org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
。這些配置信息都已eureka.client
為前綴兼呵。我們針對一些常用的配置信息做一些進一步的介紹和說明兔辅。
指定注冊中心
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
,
當構建高可用的服務注冊中心集群時击喂,可以為value的值配置多個注冊中心地址维苔,以逗號分隔,如:eureka.client.service-url.defaultZone=http://localhost:8761/eureka/,eureka.client.service-url.defaultZone=http://localhost:8762/eureka/
為了服務注冊中心的安全考慮懂昂,可以為注冊中心加上安全校驗介时,在配置serviceUrl的時候,value的值格式如下:http://<username>:<password>@localhost:8761/eureka/。其中沸柔,<username>為安全校驗信息的用戶名循衰,<password>為該用戶的密碼。
其他配置
下面整理了org.springframework.cloud.netflix.eureka.EurekaClientConfigBean
中定義的常用配置參數(shù)以及對應的說明和默認值勉失,這些參數(shù)均已erureka.client為前綴,我們可以看下EurekaClientConfigBean
的定義
public static final String PREFIX = "eureka.client";
參數(shù)名 | 說明 | 默認值 |
---|---|---|
eureka.client.enabled | 標志原探,指示啟用了Eureka客戶端乱凿。 | true |
eureka.client.encoder-name | 這是一個臨時配置,一旦最新的編解碼器穩(wěn)定下來咽弦,就可以刪除(因為只有一個) | ? |
eureka.client.register-with-eureka | 此實例是否應向eureka服務器注冊其信息以供其他人發(fā)現(xiàn)徒蟆。在某些情況下,您不希望您的實例被發(fā)現(xiàn)型型,而您只是希望發(fā)現(xiàn)其他實例段审。 | true |
eureka.client.registry-fetch-interval-seconds | 指示從eureka服務器獲取注冊表信息的頻率(秒)。 | 30 |
eureka.client.instance-info-replication-interval-seconds | 更新實例信息的變化到Eureka服務端的間隔時間闹蒜,單位為秒 | 30 |
eureka.client.eureka-server-read-timeout-seconds | 讀取Eureka Server的超時時間寺枉,單位秒 | 8 |
eureka.client.heartbeat-executor-exponential-back-off-bound | 心跳超時重試延遲時間的最大乘數(shù)值 | 10 |
eureka.client.heartbeat-executor-thread-pool-size | 心跳連接池的初始化線程數(shù) | 2 |
eureka.client.fetch-registry | 客戶端是否應從eureka服務器獲取eureka注冊表信息。 | true |
服務實例類配置
關于服務實例類的信息我們可以看org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean
源碼绷落,這些信息以eureka.instance
為前綴姥闪。針對常用配置做一些講解
元數(shù)據(jù)
EurekaInstanceConfigBean的配置中,有一大部分內(nèi)容都是針對服務實力元數(shù)據(jù)(用來描述自身服信息的對象砌烁,包括服務名稱筐喳,實例名稱,ip函喉,端口等,以及一些用于負載均衡策略或是其他特殊用途的自定義元數(shù)據(jù)信息)的配置避归。我們可以通過eureka.instance.<properties>=<value>的格式對標準化的元數(shù)據(jù)直接進行配置。自定義元數(shù)據(jù):eureka.instance.metaMap.<key>=<value>管呵。如eureka.instance.metaMap.zone=shanghai
實例名配置
InstanceInfo中的instanceId屬性梳毙。區(qū)分同一服務中不同實例的唯一標識。在Spring Cloud Eureka的配置中捐下,針對同一主機上啟動多個實例的情況顿天,對實例名的默認命名組了更為合理的擴展,它采用了如下規(guī)則:
${spring.cloud.client.hostname}:${spring.application.name}:${spring.application.instance_id:${server.port}}
對于實例名的命名規(guī)則蔑担,我們可以通過eureka.instance.instanceId參數(shù)配置
如:eureka.instance.instanceId=${spring.application.name}:${random.int}
,這樣子可以解決同一主機上牌废,不指定端口就能輕松啟動多個實例的效果。
端點配置
為了服務的正常運行啤握,我們必須確保Eureka客戶端的/health端點在發(fā)送元數(shù)據(jù)的時候鸟缕,是一個能被注冊中心訪問的地址,否則服務注冊中心不會根據(jù)應用的健康檢查來更改狀態(tài)(僅當開啟healthcheck功能時,以該端點信息作為健康檢查標準)有時候為了安全考慮懂从,也有可能修改/info和/heath端點的原始路徑授段。這個時候,我們需要做一些特殊的配置
#endpoints.info.path=/appInfo棄用
#endpoints.health.path==/checkHealth 棄用番甩,可以使用如下配置
management.endpoints.web.path-mapping.info=/appInfo
management.endpoints.web.path-mapping.health=/checkHealth
eureka.instance.status-page-url-path=${management.endpoints.web.path-mapping.info}
eureka.instance.health-check-url-path=${management.endpoints.web.path-mapping.health}
當客戶端服務以https方式暴露服務和監(jiān)控端點時侵贵,相對路徑的配置方式就無法滿足需求了。所以Spring Cloud Eureka還提供了絕對路徑的配置參數(shù)缘薛,具體示例如下:
eureka.instance.home-page-url=https://${eureka.instance.hostname}/home
eureka.instance.health-check-url=https://${eureka.instance.hostname}/health
eureka.instance.status-page-url=https://${eureka.instance.hostname}/info
健康檢查
????????默認情況下, Eureka中各個服務實例的健康檢測并不是通過 spring-boot- actuator模塊的/ health端點來實現(xiàn)的,而是依靠客戶端心跳的方式來保持服務實例的存活窍育。在Eureka的服務續(xù)約與剔除機制下,客戶端的健康狀態(tài)從注冊到注冊中心開始都會處于UP狀態(tài),除非心跳終止一段時間之后,服務注冊中心將其剔除。默認的心跳實現(xiàn)方式可以有效檢查客戶端進程是否正常運作,但卻無法保證客戶端應用能夠正常提供服務宴胧。由于大多數(shù)微服務應用都會有一些其他的外部資源依賴,比如數(shù)據(jù)庫漱抓、緩存、消息代理等,如果我的應用與這些外部資源無法聯(lián)通的時候,實際上已經(jīng)不能提供正常的對外服務了,但是因為客戶端心跳依然在運行,所以它還是會被服務消費者調(diào)用,而這樣的調(diào)用實際上并不能獲得預期的結果恕齐。
????????在 Spring Cloud Eureka中,我們可以通過簡單的配置,把 Eureka客戶端的健康檢測交給 spring-boot- actuator模塊的/ health端點,以實現(xiàn)更加全面的健康狀態(tài)維護乞娄。詳細的配置步驟如下所示:
- 在pom,xm1中引入 spring-boot- starter- actuator模塊的依賴。
- 在 application, properties中增加參數(shù)配置 eureka.client.healthcheck.enabled=true显歧。
- 如果客戶端的/ health端點路徑做了一些特殊處理,請參考前文介紹端點配置時的方法進行配置,讓服務注冊中心可以正確訪問到健康檢測端點仪或。