• 通俗易懂的阿里Sentinel源码分析:如何向控制台发送心跳包?


    源码分析

    public class Env {
        public static final Sph sph = new CtSph();
        static {
            // 在Env类的静态代码块中,
            // 触发了一系列初始化操作,
            // 其中就包括发送心跳包的初始化。
            // 如果Env类一直没有被用到,
            // 那么不会触发该初始操作。
            // 这也印证了官方的“确保客户端有访问量,
            // 才开始向控制台发送心跳包”的说法,
            // 因为有访问量就会用到Env类。
            InitExecutor.doInit();
        }
    }
    

    InitExecutor.doInit方法的核心源码:

    // 通过SPI获取实现了InitFunc接口的实现类,
    // 其中初始化发送心跳包的类是HeartbeatSenderInitFunc。
    ServiceLoader<InitFunc> loader = ServiceLoaderUtil.getServiceLoader(InitFunc.class);
    List<OrderWrapper> initList = new ArrayList<OrderWrapper>();
    // 按照InitOrder注解的值对实现类进行排序
    for (InitFunc initFunc : loader) {
        RecordLog.info("Found init func: " + initFunc.getClass().getCanonicalName());
        insertSorted(initList, initFunc);
    }
    // 按照顺序调用每一个实现类的init方法,
    // 其中也包括HeartbeatSenderInitFunc实现类。
    for (OrderWrapper w : initList) {
        w.func.init();
        RecordLog.info(String.format("Executing %s with order %d",
            w.func.getClass().getCanonicalName(), w.order));
    }
    

    HeartbeatSenderInitFunc.init方法的源码:

    // 通过SPI获取HeartbeatSender的实现类,
    // 默认的实现类是SimpleHttpHeartbeatSender。
    HeartbeatSender sender = HeartbeatSenderProvider.getHeartbeatSender();
    if (sender == null) {
        RecordLog.warn("WARN: No HeartbeatSender loaded");
        return;
    }
    // 初始化一个支持定时及周期性任务执行的线程池
    initSchedulerIfNeeded();
    // 获取发送心跳包的时间间隔,如果没有配置
    //则调用HeartbeatSender.intervalMs方法获取。
    // 在SimpleHttpHeartbeatSender类中,
    // intervalMs返回的数值是10000,也就是10秒。
    long interval = retrieveInterval(sender);
    setIntervalIfNotExists(interval);
    // 设置周期性任务
    scheduleHeartbeatTask(sender, interval);
    

    HeartbeatSenderInitFunc.scheduleHeartbeatTask方法的核心源码:

    pool.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            try {             
                // 每隔interval毫秒,
                // 执行一次sender的sendHeartbeat方法。
                sender.sendHeartbeat();
            } catch (Throwable e) {
                RecordLog.warn("Send heartbeat error", e);
            }
        }
    }, 5000, interval, TimeUnit.MILLISECONDS);
    

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    SimpleHttpHeartbeatSender.sendHeartbeat方法的核心源码:

    // 通过csp.sentinel.dashboard.server配置,
    // 获取第一个服务端的IP和端口
    InetSocketAddress addr = getAvailableAddress();
    if (addr == null) {
        return false;
    }
    
    SimpleHttpRequest request = new SimpleHttpRequest(addr, HEARTBEAT_PATH);
    // 构建心跳包的参数,
    // 包括客户端IP、端口、应用名称等信息。
    request.setParams(heartBeat.generateCurrentMessage());
    try {
        // 向服务端发送POST请求
        SimpleHttpResponse response = httpClient.post(request);
        // 状态码为200时,返回true。
        if (response.getStatusCode() == OK_STATUS) {
            return true;
        }
    } catch (Exception e) {
        RecordLog.warn("Failed to send heartbeat to " + addr + " : ", e);
    }
    return false;
    

    调用流程

    欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。

    分析结果

    在客户端首次调用后,默认为每隔10秒向控制台发送心跳包。
    可以通过SentinelConfig.setConfig方法修改间隔配置,比如,把心跳包发送时间间隔改为30秒:

    SentinelConfig.setConfig(TransportConfig.HEARTBEAT_INTERVAL_MS, "30000");
    

    另外,热更新控制台的IP和端口也有可能实现,比如:先修改csp.sentinel.dashboard.server的配置值,然后再调用SimpleHttpHeartbeatSender的getDefaultConsoleIps方法。

    微信公众号:万猫学社

    微信扫描二维码

    获得更多Java技术干货

  • 相关阅读:
    如何去掉流氓网站http://www.2345.com/?177
    『ExtJS』01 004. ExtJS 4 确定函数的作用域
    『Java』Servlet 最简教程
    『Java』最简教程
    『ExtJS』01 002. ExtJS 4 类的继承
    『ExtJS』01 003. ExtJS 4 类的混合
    『ExtJS』01 006. ExtJS 4 组件的别名
    『ExtJS』01 007. ExtJS 4 查找组件
    『ExtJS』01 005. ExtJS 4 类的‘Import’
    『ExtJS』01 001. ExtJS 4 类的定义
  • 原文地址:https://www.cnblogs.com/heihaozi/p/13211749.html
Copyright © 2020-2023  润新知