我是靠谱客的博主 乐观纸鹤,最近开发中收集的这篇文章主要介绍Eureka心跳检测,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

注册中心的心跳机制有两种形式:客户端主动上报和客户端被动响应。Eureka属于是主动上报类型的,Client通过renew机制频繁的向Server发送消息,通知Server它还活着,不要将其从服务列表中剔除,但是我们renew仅仅是监控Client是否存活,并不会去检测Client依赖的服务是否存活

image-20200410233537737

从图中我们发现Client123和Client456两个客户端均依赖了第三方组件,并且MySQL同时宕机了。

  • Client123使用了Eureka自带的renew机制,renew最基础的就是调一下Server的/apps/{appName}/{instanceId}?status=&lastDirtyTimestamp=接口,正常情况下Client启动后的status为UP,所以只要Client自身服务不出问题,永远都是UP,默认的指示器是CompositeHealthIndicator,默认的管理器为EurekaHealthCheckHandler
  • Client456通过扩展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();
}

方法调用流程图

image-20200411021953543

自定义健康监控

  1. 自定义监控组件

    @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;
                }
            }
        }
    
    }
    
  2. 自定义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();
            }
        }
    }
    
  3. 自定义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;
        }
    }
    

    方法调用流程图

    image-20200411021933621

区别

我们打开Redis服务,启动Eureka Server、Client123和Client456。

  • Redis运行中

    Redis正常运行时,两个服务都处于正常情况

    image-20200411022923590

  • Redis停止

    将Redis服务停掉,等待一个renew周期后,服务状态发生变化,使用默认HealthCheckHandler的CUSER-SERVICE的status仍然为UP,而我们自定义HealthCheckHandler的EUREKA-HEALTH服务的status已经变成了DOWN,符合正常要求。

    image-20200411023355326

总结

在实际的生产工作中,尽量不要使用默认的HealthCheckHandler,不然就算是我们项目的MySQL、Redis、MongoDB、MQ都挂掉了,只要项目的进程还存活,那么status就很大的可能是UP,但实际上项目已经无法正常提供服务了,会给我们的项目带来很大的麻烦。

最后

以上就是乐观纸鹤为你收集整理的Eureka心跳检测的全部内容,希望文章能够帮你解决Eureka心跳检测所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部