zoukankan      html  css  js  c++  java
  • 通俗易懂的阿里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技术干货

  • 相关阅读:
    LeetCode 326. Power of Three
    LeetCode 324. Wiggle Sort II
    LeetCode 322. Coin Change
    LeetCode 321. Create Maximum Number
    LeetCode 319. Bulb Switcher
    LeetCode 318. Maximum Product of Word Lengths
    LeetCode 310. Minimum Height Trees (DFS)
    个人站点大开发!--起始篇
    LeetCode 313. Super Ugly Number
    LeetCode 309. Best Time to Buy and Sell Stock with Cooldown (DP)
  • 原文地址:https://www.cnblogs.com/heihaozi/p/13211749.html
Copyright © 2011-2022 走看看