採集Hystrix線程池指標並使用influxDB+Grafana實時監控(HystrixDashboard升級方案)

背景

我們的網關採用了Hystrix來向業務方提供的服務發送http請求,之前嘗試採用官方的Turbine+HystrixDashboard來監控Hystrix命令和線程池的指標,發現由於默認採集指標數據過多,在併發量比較高的情況下對網關應用Jvm內存和GC影響較大。因此在分析HystrixDashboard的數據採集過程後(相關文章:HystrixMetrics指標採集源碼解讀),決定自己來實現一套Hystrix指標監控。

根據在網上查找相關資料,我決定採用InfluxDB來存儲指標數據,然後使用Grafana構建實時圖表進行監控。

  • InfluxDB是一個當下比較流行的時序數據庫,InfluxDB使用 Go 語言編寫,無需外部依賴,安裝配置非常方便,適合構建大型分佈式系統的監控系統(InfluxDB官網
  • Grafana是一個開源的度量分析與可視化套件。經常被用作基礎設施的時間序列數據和應用程序分析的可視化。支持許多不同的數據源:Graphite,InfluxDB,OpenTSDB,Prometheus,Elasticsearch,CloudWatch和KairosDB等(grafana官網

最終效果

先提前看下效果圖(以Hystrix線程池的rollingMaxActiveThreads指標數據爲例),可查看每臺網關實例的各個線程池組當前窗口期最大併發線程,用來關注不同業務服務的實時調用量,便於後續調整線程池大小及超時時間:

一、部署InfluxDB、Grafana

這裏以CentOS系統下的yum安裝爲例,便於快速部署,其他下載安裝方式參考官網:

1. 安裝InfluxDB

# 1. 下載安裝包
wget https://dl.influxdata.com/influxdb/releases/influxdb-1.7.6.x86_64.rpm
# 2. 使用yum安裝
sudo yum localinstall influxdb-1.7.6.x86_64.rpm
# 3. 啓動服務(默認使用8086端口)
service influxdb start

2. 安裝Grafana

# 1. 下載安裝包
wget https://dl.grafana.com/oss/release/grafana-6.2.0-1.x86_64.rpm
# 2. 使用yum安裝
sudo yum localinstall grafana-6.2.0-1.x86_64.rpm
# 3. 啓動服務(默認使用3000端口)
service grafana-server start

二、上報指標數據

1.引入InfluxDB的java client依賴:

<dependency>
    <groupId>org.influxdb</groupId>
    <artifactId>influxdb-java</artifactId>
    <version>2.15</version>
</dependency>

2.InfluxDB數據庫配置

# 數據庫地址、用戶名、密碼
influxDB.serverAddr=http://172.xx.xx.xx:8086
influxDB.username=root
influxDB.password=root
# 庫名
influxDB.dataBase=gateway_hystrix_test
# 數據保留策略名
influxDB.retentionPolicyName=3_days
# 數據保留策略,3d:保留3天
influxDB.retentionPolicy=3d

創建並初始化InfluxDB實例,後續通過引入InfluxDB對象來進行相關數據庫操作(類SQL語句):

@Configuration
public class InfluxDbConfig {

   @Value("${influxDB.serverAddr}")
   private String serverAddr;
   @Value("${influxDB.username}")
   private String username;
   @Value("${influxDB.password}")
   private String password;
   @Value("${influxDB.dataBase}")
   private String dataBase;
   @Value("${influxDB.retentionPolicyName}")
   private String retentionPolicyName;
   @Value("${influxDB.retentionPolicy}")
   private String retentionPolicy;

   @Bean
   public InfluxDB influxDB() {
      // 連接influxDB數據庫
      InfluxDB influxDB = InfluxDBFactory.connect(serverAddr, username, password);
      // 創建數據庫
      influxDB.query(new Query("CREATE DATABASE " + dataBase));
      influxDB.setDatabase(dataBase);
      // 創建數據保留策略
      influxDB.query(new Query("CREATE RETENTION POLICY \"" + retentionPolicyName + "\" ON \"" + dataBase
            + "\" DURATION " + retentionPolicy + " REPLICATION 1 DEFAULT"));
      influxDB.setRetentionPolicy(retentionPolicyName);
      return influxDB;
   }
}

3. 採集並上報指標數據

通過@Scheduled每秒上報,這裏只採集了HystrixThreadPool指標,如果有額外的需求,還可以通過HystrixCommandMetricsHystrixCollapserMetrics來獲取其他Hystrix指標數據:

  • HystrixCommandMetrics:獲取Hystrix命令執行情況(成功/失敗)
  • HystrixThreadPoolMetrics:獲取Hystrix線程池指標
  • HystrixCollapserMetrics:獲取Hystrix合併命令執行情況
@Component
public class HystrixMetricRecorder {
   
   private static final Logger logger = LoggerFactory.getLogger(HystrixMetricRecorder.class);
  
   private String host;
   @Value("${server.port}")
   private int port;
   
   @Autowired
   private InfluxDB influxDB;
   @PostConstruct
   public void init() {
      try {
         host = InetAddress.getLocalHost().getHostAddress();
      } catch (Exception e) {
         logger.error("get host&port error", e);
      }
   }
   
   @Scheduled(fixedRate = 1000)
   public void threadPoolMetricsRecord() {
      // 獲取Hystrix線程池指標數據(Hystrix自動收集的)
      Collection<HystrixThreadPoolMetrics> threadPoolMetrics = HystrixThreadPoolMetrics.getInstances();
      for (HystrixThreadPoolMetrics threadPoolMetric : threadPoolMetrics) {
         // 線程池組名
         String groupName = threadPoolMetric.getThreadPoolKey().name();
         // 當前活躍線程數
         int currentActive = threadPoolMetric.getCurrentActiveCount().intValue();
         // 當前線程池大小
         int currentPoolSize = threadPoolMetric.getCurrentPoolSize().intValue();
         // 窗口期(默認最近10s)最大併發線程數
         long rollingMaxActiveThreads = threadPoolMetric.getRollingMaxActiveThreads();
         // 窗口期(默認最近10s)線程拒絕數
         long rollingCountThreadsRejected = threadPoolMetric.getRollingCountThreadsRejected();
         /*
            measurement相當於表名
            tag是用於統計或分類的參數,這裏用ip+端口進行標記,用於後續圖表展示
            field相當於列,存儲各類指標值
          */
         influxDB.write(Point.measurement("threadPool")
               .time(System.currentTimeMillis(), TimeUnit.MILLISECONDS)
               .tag("host", host)
               .tag("port", port + "")
               .tag("addr", host + ":" + port)
               .tag("group", groupName)
               .addField("currentActive", currentActive)
               .addField("currentPoolSize", currentPoolSize)
               .addField("rollingMaxActiveThreads", rollingMaxActiveThreads)
               .addField("rollingCountThreadsRejected", rollingCountThreadsRejected).build());
      }
   }
}

4.檢查InfluxDB數據

啓動應用,通過http API可以看到相關庫和表已經自動創建了

再確認指標數據都已成功上報:

三、配置Grafana數據可視化

Grafana端口爲3000,默認用戶名、密碼都是admin

1.創建數據源

Configuration -> Data Sources -> 選擇InfluxDB
根據自己InfluxDB的部署參數來配置數據源

2.創建Panel

3.配置數據查詢

首先創建一個動態變量addr,這個是根據上報數據的tag=addr(ip+端口)來查詢的,用於後面自動分組展示數據。

然後就是通過設置具體的數據展示參數:

  • 選擇db=threadPool,retentionPolicy=3_days
  • 設置動態分組條件,將tag addr的值設置條件 = 變量$addr
  • 選擇需要展示的字段值:rollingMaxActiveThreads,取最大值
  • 按時間和tag分組,並將無上報的時間點填充值爲0

配置Repeating:選擇addr,這樣可以根據ip和端口的不同自動創建多個圖表

配置全部完成,就可以通過選擇時間區間段和刷新頻率,來查看自己的監控圖表啦。

總結

其實通過InfluxDB+Grafana監控服務器指標或Jvm指標等通用指標數據的教程有很多,這裏主要是幫助大家如何通過InfluxDB的java客戶端來上報自定義的指標數據,可以是文中的Hystrix的線程執行指標,也可以是各類業務指標。總之,最終目的就是希望通過可視化的界面,來快速掌握分析應用的運行狀況,來進行實時監控乃至後續的優化,希望這篇文章能幫到你。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章