1. 程式人生 > 實用技巧 >通俗易懂的阿里Sentinel原始碼分析:如何向控制檯傳送心跳包?

通俗易懂的阿里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技術乾貨