序
本文主要研究一下EurekaHealthCheckHandler
HealthCheckHandler
eureka-client-1.8.8-sources.jar!/com/netflix/appinfo/HealthCheckHandler.java
/**
* This provides a more granular healthcheck contract than the existing {@link HealthCheckCallback}
*
* @author Nitesh Kant
*/
public interface HealthCheckHandler {
InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus);
}
netflix的eureka-client提供了HealthCheckHandler接口,用来对获取服务实例的健康状态
HealthCheckCallbackToHandlerBridge
eureka-client-1.8.8-sources.jar!/com/netflix/appinfo/HealthCheckCallbackToHandlerBridge.java
@SuppressWarnings("deprecation")
public class HealthCheckCallbackToHandlerBridge implements HealthCheckHandler {
private final HealthCheckCallback callback;
public HealthCheckCallbackToHandlerBridge() {
callback = null;
}
public HealthCheckCallbackToHandlerBridge(HealthCheckCallback callback) {
this.callback = callback;
}
@Override
public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus) {
if (null == callback || InstanceInfo.InstanceStatus.STARTING == currentStatus
|| InstanceInfo.InstanceStatus.OUT_OF_SERVICE == currentStatus) { // Do not go to healthcheck handler if the status is starting or OOS.
return currentStatus;
}
return callback.isHealthy() ? InstanceInfo.InstanceStatus.UP : InstanceInfo.InstanceStatus.DOWN;
}
}
这个类被标记为废弃,如果没有callback,或者当前状态是STARTING或OUT_OF_SERVICE,都会返回当前状态;否则才会调用callback的isHealthy方法来判断是UP还是DOWN.也就是说如果没有callback,一开始启动的时候是UP,则之后都是返回UP
registerHealthCheck
eureka-client-1.8.8-sources.jar!/com/netflix/discovery/DiscoveryClient.java
/**
* Register {@link HealthCheckCallback} with the eureka client.
*
* Once registered, the eureka client will invoke the
* {@link HealthCheckCallback} in intervals specified by
* {@link EurekaClientConfig#getInstanceInfoReplicationIntervalSeconds()}.
*
* @param callback app specific healthcheck.
*
* @deprecated Use
*/
@Deprecated
@Override
public void registerHealthCheckCallback(HealthCheckCallback callback) {
if (instanceInfo == null) {
logger.error("Cannot register a listener for instance info since it is null!");
}
if (callback != null) {
healthCheckHandler = new HealthCheckCallbackToHandlerBridge(callback);
}
}
@Override
public void registerHealthCheck(HealthCheckHandler healthCheckHandler) {
if (instanceInfo == null) {
logger.error("Cannot register a healthcheck handler when instance info is null!");
}
if (healthCheckHandler != null) {
this.healthCheckHandler = healthCheckHandler;
// schedule an onDemand update of the instanceInfo when a new healthcheck handler is registered
if (instanceInfoReplicator != null) {
instanceInfoReplicator.onDemandUpdate();
}
}
}
registerHealthCheckCallback被标记为废弃,原因是它默认注册了一个HealthCheckCallbackToHandlerBridge;后续是在这个方法里头处理fallback逻辑
getHealthCheckHandler
eureka-client-1.8.8-sources.jar!/com/netflix/discovery/DiscoveryClient.java
@Override
public HealthCheckHandler getHealthCheckHandler() {
if (healthCheckHandler == null) {
if (null != healthCheckHandlerProvider) {
healthCheckHandler = healthCheckHandlerProvider.get();
} else if (null != healthCheckCallbackProvider) {
healthCheckHandler = new HealthCheckCallbackToHandlerBridge(healthCheckCallbackProvider.get());
}
if (null == healthCheckHandler) {
healthCheckHandler = new HealthCheckCallbackToHandlerBridge(null);
}
}
return healthCheckHandler;
}
这里判断,如果最后healthCheckHandler为null,则会创建HealthCheckCallbackToHandlerBridge
HealthCheckCallback
eureka-client-1.8.8-sources.jar!/com/netflix/appinfo/HealthCheckCallback.java
@Deprecated
public interface HealthCheckCallback {
/**
* If false, the instance will be marked
* {@link InstanceInfo.InstanceStatus#DOWN} with eureka. If the instance was
* already marked {@link InstanceInfo.InstanceStatus#DOWN} , returning true
* here will mark the instance back to
* {@link InstanceInfo.InstanceStatus#UP}.
*
* @return true if the call back returns healthy, false otherwise.
*/
boolean isHealthy();
}
HealthCheckCallback目前被标记为废弃,可以理解为最后的healthCheckHandler = new HealthCheckCallbackToHandlerBridge(null);
EurekaServiceRegistry
spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/serviceregistry/EurekaServiceRegistry.java
@Override
public void register(EurekaRegistration reg) {
maybeInitializeClient(reg);
if (log.isInfoEnabled()) {
log.info("Registering application " + reg.getInstanceConfig().getAppname()
+ " with eureka with status "
+ reg.getInstanceConfig().getInitialStatus());
}
reg.getApplicationInfoManager()
.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
reg.getHealthCheckHandler().ifAvailable(healthCheckHandler ->
reg.getEurekaClient().registerHealthCheck(healthCheckHandler));
}
这个方法判断,如果有healthCheckHandler实例,则才会调用registerHealthCheck去注册。
EurekaDiscoveryClientConfiguration
spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/EurekaDiscoveryClientConfiguration.java
@Configuration
@EnableConfigurationProperties
@ConditionalOnClass(EurekaClientConfig.class)
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
public class EurekaDiscoveryClientConfiguration {
class Marker {}
@Bean
public Marker eurekaDiscoverClientMarker() {
return new Marker();
}
@Configuration
@ConditionalOnClass(RefreshScopeRefreshedEvent.class)
protected static class EurekaClientConfigurationRefresher {
@Autowired(required = false)
private EurekaClient eurekaClient;
@Autowired(required = false)
private EurekaAutoServiceRegistration autoRegistration;
@EventListener(RefreshScopeRefreshedEvent.class)
public void onApplicationEvent(RefreshScopeRefreshedEvent event) {
//This will force the creation of the EurkaClient bean if not already created
//to make sure the client will be reregistered after a refresh event
if(eurekaClient != null) {
eurekaClient.getApplications();
}
if (autoRegistration != null) {
// register in case meta data changed
this.autoRegistration.stop();
this.autoRegistration.start();
}
}
}
@Configuration
@ConditionalOnProperty(value = "eureka.client.healthcheck.enabled", matchIfMissing = false)
protected static class EurekaHealthCheckHandlerConfiguration {
@Autowired(required = false)
private HealthAggregator healthAggregator = new OrderedHealthAggregator();
@Bean
@ConditionalOnMissingBean(HealthCheckHandler.class)
public EurekaHealthCheckHandler eurekaHealthCheckHandler() {
return new EurekaHealthCheckHandler(this.healthAggregator);
}
}
}
默认eureka.client.healthcheck.enabled为false,如果设置为true的话则会注入EurekaHealthCheckHandler
EurekaHealthCheckHandler
spring-cloud-netflix-eureka-client-2.0.0.RC1-sources.jar!/org/springframework/cloud/netflix/eureka/EurekaHealthCheckHandler.java
public class EurekaHealthCheckHandler implements HealthCheckHandler, ApplicationContextAware, InitializingBean {
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING =
new HashMap<Status, InstanceInfo.InstanceStatus>() {{
put(Status.UNKNOWN, InstanceStatus.UNKNOWN);
put(Status.OUT_OF_SERVICE, InstanceStatus.OUT_OF_SERVICE);
put(Status.DOWN, InstanceStatus.DOWN);
put(Status.UP, InstanceStatus.UP);
}};
private final CompositeHealthIndicator healthIndicator;
private ApplicationContext applicationContext;
public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
this.healthIndicator = new CompositeHealthIndicator(healthAggregator);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
//ignore EurekaHealthIndicator and flatten the rest of the composite
//otherwise there is a never ending cycle of down. See gh-643
if (entry.getValue() instanceof DiscoveryCompositeHealthIndicator) {
DiscoveryCompositeHealthIndicator indicator = (DiscoveryCompositeHealthIndicator) entry.getValue();
for (DiscoveryCompositeHealthIndicator.Holder holder : indicator.getHealthIndicators()) {
if (!(holder.getDelegate() instanceof EurekaHealthIndicator)) {
healthIndicator.addHealthIndicator(holder.getDelegate().getName(), holder);
}
}
}
else {
healthIndicator.addHealthIndicator(entry.getKey(), entry.getValue());
}
}
}
@Override
public InstanceStatus getStatus(InstanceStatus instanceStatus) {
return getHealthStatus();
}
protected InstanceStatus getHealthStatus() {
final Status status = getHealthIndicator().health().getStatus();
return mapToInstanceStatus(status);
}
protected InstanceStatus mapToInstanceStatus(Status status) {
if (!STATUS_MAPPING.containsKey(status)) {
return InstanceStatus.UNKNOWN;
}
return STATUS_MAPPING.get(status);
}
protected CompositeHealthIndicator getHealthIndicator() {
return healthIndicator;
}
}
可以看到在afterPropertiesSet的时候,将整个springboot的healthIndicator添加进来并转化映射为eureka的InstanceStatus,组合为CompositeHealthIndicator。而client的health check则会调用这个getStatus接口,返回的是compositeHealthIndicator的健康状态。
小结
eureka client的health check默认是false,即最后使用的是HealthCheckCallbackToHandlerBridge,即HealthCheckCallbackToHandlerBridge(null),callback为null,则默认返回的都是启动时注册的状态,一般是UP。如果开启eureka.client.healthcheck.enabled=true则会将springboot的actuator的health indicator都纳入health check当中。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。