【服務離線】記一次組件引入造成actuator下線問題

SpringBoot Admin可以看作是Spring actuator 端點監控的一個UI界面,可以很方便的查看服務的運行情況。

部分服務不在線

【服務離線】記一次組件引入造成actuator下線問題

如上圖,在項目整合了部分組件後,出現狀態顯示不在線,但應用還是能夠正常的對外提供服務。

  • 我們知道 應用展示的在線狀態是讀取的 Spring actuator health endpoint數據
<code>curl http://127.0.0.1:5002/actuator/health

{"status":"DOWN"} /<code>
  • 此時無法通過 SpringBoot Admin 無法獲取更多的細節, 建議開發環境開啟端點的詳細信息。
<code>management:
endpoints:
web:
exposure:
include: '*'
endpoint:
health:
show-details: always #dev open/<code>
  • 再次嘗試訪問, 輸出了全部組件的狀態,可以明確的看到由於 sentinel 狀態不對影響全局狀態為 down
<code>curl http://127.0.0.1:5002/actuator/health

{"status":"DOWN","components":{"discoveryComposite":{"status":"UP","components":{"discoveryClient":{"status":"UP","details":{"services":["pigx-upms-biz","pigx-tx-manager","pigx-daemon-elastic-job","pigx-mp-platform","pigx-daemon-quartz","pigx-gateway","pigx-auth","pigx-pay-platform","pigx-codegen","pigx-oa-platform","pigx-monitor"]}}}},"diskSpace":{"status":"UP","details":{"total":42927636480,"free":21334122496,"threshold":10485760}},"nacosConfig":{"status":"UP"},"nacosDiscovery":{"status":"UP"},"ping":{"status":"UP"},"reactiveDiscoveryClients":{"status":"UP","components":{"Simple Reactive Discovery Client":{"status":"UP","details":{"services":[]}}}},"redis":{"status":"UP","details":{"version":"5.0.7"}},"refreshScope":{"status":"UP"},"sentinel":{"status":"DOWN","details":{"dataSource":{},"enabled":true,"dashboard":{"description":"pigx-sentinel:5020 can't be connected","status":"DOWN"}}}}}/<code>

sentinel dashboadr can't be connected

  • SentinelHealthIndicator.doHealthCheck 來看下 sentinel 的健康檢查是如何處理的
<code>protected void doHealthCheck(Health.Builder builder) throws Exception {
\tMap<string> detailMap = new HashMap<>();

\t\t// 獲取心跳發送器
\t\tHeartbeatSender heartbeatSender = HeartbeatSenderProvider
\t\t\t\t.getHeartbeatSender();
\t\t// 發送心跳
\t\tboolean result = heartbeatSender.sendHeartbeat();
\t\tif (result) {
\t\t // 成功標記為UP
\t\t\tdetailMap.put("dashboard", Status.UP);
\t\t}
\t\telse {
\t\t // 失敗 標記為down
\t\t\tdashboardUp = false;
\t\t\tdetailMap.put("dashboard", new Status(Status.DOWN.getCode(),
\t\t\t\t\tconsoleServer + " can't be connected"));
\t\t}
\t}

\t// If Dashboard and DataSource are both OK, the health status is UP
\tif (dashboardUp && dataSourceUp) {
\t\tbuilder.up().withDetails(detailMap);
\t}
\telse {
\t\tbuilder.down().withDetails(detailMap);
\t}
}/<string>/<code>
  • SimpleHttpHeartbeatSender.sendHeartbeat 心跳發送器的處理邏輯
<code>public boolean sendHeartbeat() throws Exception {
\t
\t// 1. 判斷客戶端是和服務端是否交互 ,只有交互時dashboard 才有數據展示
\tif (TransportConfig.getRuntimePort() <= 0) {
\t\tRecordLog.info("[SimpleHttpHeartbeatSender] Runtime port not initialized, won't send heartbeat");
\t\treturn false;
\t}
\tInetSocketAddress addr = getAvailableAddress();
\tif (addr == null) {
\t\treturn false;

\t}
\t
\t// 2. 訪問dashboard 的接口
\tSimpleHttpRequest request = new SimpleHttpRequest(addr, TransportConfig.getHeartbeatApiPath());
\trequest.setParams(heartBeat.generateCurrentMessage());
\tSimpleHttpResponse response = httpClient.post(request);
\tif (response.getStatusCode() == OK_STATUS) {
\t\treturn true;
\t}
\treturn false;
}/<code>
  • 到底是上文代碼 第一步未交互被判斷為down、還是第二步訪問出錯判斷為down

查看 sentinel client 的日誌

<code>cat ~/csp/sentinel-record.log 

2020-03-23 13:54:04.634 INFO [SimpleHttpHeartbeatSender] Runtime port not initialized, won't send heartbeat

/<code>

開始是第一步沒有初始化交互造成,服務判斷為 down

sentinel 如何初始化交互

  • 初始化交互端口 commandCenter.start()
<code>public class CommandCenterInitFunc implements InitFunc {

@Override
public void init() throws Exception {
CommandCenter commandCenter = CommandCenterProvider.getCommandCenter();

if (commandCenter == null) {
RecordLog.warn("[CommandCenterInitFunc] Cannot resolve CommandCenter");
return;
}

commandCenter.beforeStart();
// 開始初始化端口交互
commandCenter.start();
RecordLog.info("[CommandCenterInit] Starting command center: "
+ commandCenter.getClass().getCanonicalName());
}
}/<code>
  • 配置啟動立即加載初始化,而不是有流量請求再初始化
<code>public class SentinelAutoConfiguration {

\t@Value("${project.name:${spring.application.name:}}")
\tprivate String projectName;

\t@Autowired
\tprivate SentinelProperties properties;

\t@PostConstruct
\tprivate void init() {

\t\t// earlier initialize
\t\tif (properties.isEager()) {
\t\t\tInitExecutor.doInit();
\t\t}

\t}/<code>
<code>spring:
application:
name: @artifactId@
cloud:
sentinel:
eager: true/<code>


作者:冷冷gg
鏈接:https://juejin.im/post/5e795b905188255e1e4ec1e3


分享到:


相關文章: