赞
踩
注册中心的心跳机制有两种形式:客户端主动上报和客户端被动响应。Eureka属于是主动上报类型的,Client通过renew机制频繁的向Server发送消息,通知Server它还活着,不要将其从服务列表中剔除,但是我们renew仅仅是监控Client是否存活,并不会去检测Client依赖的服务是否存活
从图中我们发现Client123和Client456两个客户端均依赖了第三方组件,并且MySQL同时宕机了。
/apps/{appName}/{instanceId}?status=&lastDirtyTimestamp=
接口,正常情况下Client启动后的status为UP,所以只要Client自身服务不出问题,永远都是UP,默认的指示器是CompositeHealthIndicator
,默认的管理器为EurekaHealthCheckHandler
;HealthIndicator
接口和HealthCheckHandler
接口,然后来自定义需要监控的内容在类DiscoveryClient#getHealthCheckHandler
方法中选择需要使用的健康管理器
- public HealthCheckHandler getHealthCheckHandler() {
- HealthCheckHandler healthCheckHandler = this.healthCheckHandlerRef.get();
- 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);
- }
- this.healthCheckHandlerRef.compareAndSet(null, healthCheckHandler);
- }
-
- return this.healthCheckHandlerRef.get();
- }

方法调用流程图
自定义监控组件
- @Component
- public class HealthPolicyBean implements InitializingBean {
-
- @Resource
- private RedisTemplate<String, Object> redisTemplate;
- /**
- * 调度线程池
- */
- private ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);
- /**
- * 数据库健康情况
- */
- public static boolean dbHealth = true;
- /**
- * Redis健康情况
- */
- public static boolean redisHealth = true;
- /**
- * MongoDB健康情况
- */
- public static boolean mongoHealth = true;
-
- @Override
- public void afterPropertiesSet() throws Exception {
- // 创建调度器
- ThreadPoolExecutor heartbeatExecutor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
- new SynchronousQueue<>(),
- new ThreadFactoryBuilder().setNameFormat("redis-HeartbeatExecutor-%d").setDaemon(true).build());
-
- TimedSupervisorTask task = new TimedSupervisorTask("redis-heartbeat", scheduled, heartbeatExecutor, 10,
- TimeUnit.SECONDS, 100, new RedisTimer());
-
- scheduled.schedule(task, 10, TimeUnit.SECONDS);
- }
-
- /**
- * 监控Redis状态
- */
- protected class RedisTimer implements Runnable {
-
- @Override
- public void run() {
- try {
- List<RedisClientInfo> clientList = redisTemplate.getClientList();
- if (clientList == null || clientList.isEmpty()) {
- HealthPolicyBean.redisHealth = false;
- } else {
- HealthPolicyBean.redisHealth = true;
- }
- } catch (Exception e) {
- HealthPolicyBean.redisHealth = false;
- }
- }
- }
-
- }

自定义HealthIndicator
- /**
- * Cc健康指示器
- */
- @Component
- public class CcHealthIndicator implements HealthIndicator {
-
- @Override
- public Health health() {
- if (HealthPolicyBean.dbHealth && HealthPolicyBean.redisHealth && HealthPolicyBean.mongoHealth) {
- // 当所有组件都正常时才返回UP
- return new Health.Builder(Status.UP).build();
- } else {
- return new Health.Builder(Status.DOWN).build();
- }
- }
- }

自定义HealthCheckHandler
- /**
- * Cc健康管理器
- */
- @Component
- public class CcHealthCheckHandler implements HealthCheckHandler {
-
- @Autowired
- private CcHealthIndicator ccHealthIndicator;
-
- @Override
- public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus currentStatus) {
- if (ccHealthIndicator.health().getStatus().equals(Status.UP)) {
- return InstanceInfo.InstanceStatus.UP;
- }
- return InstanceInfo.InstanceStatus.DOWN;
- }
- }

方法调用流程图
我们打开Redis服务,启动Eureka Server、Client123和Client456。
Redis运行中
Redis正常运行时,两个服务都处于正常情况
Redis停止
将Redis服务停掉,等待一个renew周期后,服务状态发生变化,使用默认HealthCheckHandler的CUSER-SERVICE的status仍然为UP,而我们自定义HealthCheckHandler的EUREKA-HEALTH服务的status已经变成了DOWN,符合正常要求。
在实际的生产工作中,尽量不要使用默认的HealthCheckHandler,不然就算是我们项目的MySQL、Redis、MongoDB、MQ都挂掉了,只要项目的进程还存活,那么status就很大的可能是UP,但实际上项目已经无法正常提供服务了,会给我们的项目带来很大的麻烦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。