SpringBoot 2.0 + InfluxDB+ Sentinel 實時監控數據存儲

  • 2019 年 10 月 3 日
  • 筆記

前言

阿里巴巴提供的控制台只是用於演示 Sentinel 的基本能力和工作流程,並沒有依賴生產環境中所必需的組件,比如持久化的後端資料庫、可靠的配置中心等。目前 Sentinel 採用記憶體態的方式存儲監控和規則數據,監控最長存儲時間為 5 分鐘,控制台重啟後數據丟失。

企業版

這裡推薦一下阿里雲的官方版,AHAS Sentinel 控制台 是 Sentinel 控制台的阿里雲上版本,提供企業級的控制台服務,包括:

  • 實時請求鏈路查看
  • 還有各種酷炫的監控圖表
  • 可靠的實時監控和歷史監控數據查詢,無需自行存儲、拉取
  • 動態規則管理/推送,無需自行配置外部數據源

免費版,可以提供 5 個節點的免費額度。開通專業版即可享受不限量節點額度。

專業版沒有實例連接限制,開通後每天前5個限流降級節點不計費,超出部分按3元/天/實例收取相應的費用。

思路

官方文檔也提供了思路,若需要監控數據持久化的功能,可以自行擴展實現 MetricsRepository 介面(0.2.0 版本),然後註冊成 Spring Bean 並在相應位置通過 @Qualifier 註解指定對應的 bean name 即可。MetricsRepository 介面定義了以下功能:

  • save 與 saveAll:存儲對應的監控數據

  • queryByAppAndResourceBetween:查詢某段時間內的某個應用的某個資源的監控數據

  • listResourcesOfApp:查詢某個應用下的所有資源

其中默認的監控數據類型為 MetricEntity,包含應用名稱、時間戳、資源名稱、異常數、請求通過數、請求拒絕數、平均響應時間等資訊。

對於監控數據的存儲,用戶需要根據自己的存儲精度,來考慮如何存儲這些監控數據。顯然我們要使用目前最流行的時序資料庫InfluxDB解決方案,不要問什麼?閉眼享受就可以了。

選型

InfluxDB是一個開源分散式時序、事件和指標資料庫。使用 Go 語言編寫,無需外部依賴。

應用:性能監控,應用程式指標,物聯網感測器數據和實時分析等的後端存儲。

  • 強大的類SQL語法

  • 內置http支援,使用http讀寫

  • 基於事件:它支援任意的事件數據

  • 無結構(無模式):可以是任意數量的列

  • 可度量性:你可以實時對大量數據進行計算

  • 持續高並發寫入、無更新、數據壓縮存儲、低查詢延時

  • 支援min, max, sum, count, mean, median 等一系列函數

  • 基於時間序列,支援與時間有關的相關函數(如最大,最小,求和等)

改造

InfluxDB 安裝

首先你得先有個 Influxdb 資料庫,建議使用 Docker 方式安裝,更多可以參考文末鏈接。

需要注意的是,從1.1.0版開始不推薦使用管理員介面,並將在1.3.0版中刪除。默認情況下禁用。如果需要,仍可以通過設置如下環境變數來啟用它。

以下埠很重要,並由InfluxDB使用。

  • 8086 HTTP API埠
  • 8083 管理員介面埠(如果已啟用,1.7.8貌似啟用也不好使),官方推薦使用chronograf

通過該命令, 生成默認配置文件:

docker run --rm influxdb influxd config > influxdb.conf

創建並運行容器:

docker run -d           -p 8086:8086           -p 8083:8083           -e INFLUXDB_ADMIN_ENABLED=true           -v $PWD/data:/var/lib/influxdb/           -v $PWD/config/influxdb.conf:/etc/influxdb/influxdb.conf:ro           --name influx           influxdb -config /etc/influxdb/influxdb.conf

生產環境一定要開啟許可權驗證,修改 influxdb.conf 配置:

[http]    enabled = true    bind-address = ":8086"    auth-enabled = true # 鑒權

創建用戶:

# 進入容器  docker exec -it influx  /bin/sh  # 連接  influx  # 創建用戶  CREATE USER admin with PASSWORD 'admin' WITH ALL PRIVILEGES

退出重新登錄:

# 用戶密碼登錄  influx -username admin -password admin  # 創建資料庫  CREATE DATABASE sentinel_log

Sentinel 控制台改造

pom.xml引入 influxdb 官方開源工具包:

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

配置文件引入:

# 自行替換 API 地址:埠  spring.influx.url=http://127.0.0.1:8086  spring.influx.user=admin  spring.influx.password=admin  spring.influx.database=sentinel_log

配置數據源:

/**   * InfluxDb 配置   * 創建者 爪哇筆記   * 網址 https://blog.52itstyle.vip   */  @Configuration  public class InfluxDbConfig {        @Value("${spring.influx.url:''}")      private String influxDBUrl;        @Value("${spring.influx.user:''}")      private String userName;        @Value("${spring.influx.password:''}")      private String password;        @Value("${spring.influx.database:''}")      private String database;        @Bean      public InfluxDB influxDB(){          InfluxDB influxDB = InfluxDBFactory.connect(influxDBUrl, userName, password);          try {              /**               * 非同步插入:               * enableBatch這裡第一個是point的個數,第二個是時間,單位毫秒               * point的個數和時間是聯合使用的,如果滿100條或者2000毫秒               * 滿足任何一個條件就會發送一次寫的請求。               */              influxDB.setDatabase(database)                      .enableBatch(100,2000, TimeUnit.MILLISECONDS);          } catch (Exception e) {              e.printStackTrace();          } finally {              influxDB.setRetentionPolicy("autogen");          }          influxDB.setLogLevel(InfluxDB.LogLevel.BASIC);          return influxDB;      }  }

實現 MetricsRepository 介面,重寫實現:

/**   * 數據CURD   * 創建者 爪哇筆記   * 網址 https://blog.52itstyle.vip   */  @Component("inInfluxdbMetricsRepository")  public class InInfluxdbMetricsRepository implements MetricsRepository<MetricEntity> {        @Autowired      public InfluxDB influxDB;        @Override      public synchronized void save(MetricEntity metric) {         //省略程式碼,太長了,參考記憶體寫法,參考 saveAll 這裡是單條插入      }        @Override      public synchronized void saveAll(Iterable<MetricEntity> metrics) {          if (metrics == null) {              return;          }          BatchPoints batchPoints = BatchPoints.builder()                  .tag("async", "true")                  .consistency(InfluxDB.ConsistencyLevel.ALL)                  .build();          metrics.forEach(metric->{              Point point = Point                      .measurement("sentinelInfo")                      //這裡使用微妙、如果還有覆蓋數據就使用納秒,保證 time 和 tag 唯一就可以                      .time(System.currentTimeMillis(), TimeUnit.MICROSECONDS)                      .tag("app",metric.getApp())//tag 數據走索引                      .addField("gmtCreate", metric.getGmtCreate().getTime())                      .addField("gmtModified", metric.getGmtModified().getTime())                      .addField("timestamp", metric.getTimestamp().getTime())                      .addField("resource", metric.getResource())                      .addField("passQps", metric.getPassQps())                      .addField("successQps", metric.getSuccessQps())                      .addField("blockQps", metric.getBlockQps())                      .addField("exceptionQps", metric.getExceptionQps())                      .addField("rt", metric.getRt())                      .addField("count", metric.getCount())                      .addField("resourceCode", metric.getResourceCode())                      .build();              batchPoints.point(point);          });          //批量插入          influxDB.write(batchPoints);      }        @Override      public synchronized List<MetricEntity> queryByAppAndResourceBetween(String app, String resource, long startTime, long endTime) {         //省略程式碼,太長了,參考記憶體寫法      }        @Override      public synchronized List<String> listResourcesOfApp(String app) {         //省略程式碼,太長了,參考記憶體寫法      }  }

分別修改 MetricFetcher 和 MetricController中 metricStore 的注入方式,使用 Influxdb 實現:

/**   * 注入   * 創建者 爪哇筆記   * 網址 https://blog.52itstyle.vip   */  @Autowired  @Qualifier("inInfluxdbMetricsRepository")  private MetricsRepository<MetricEntity> metricStore;

配置完成後,我們重啟控制台,然後訪問客戶端項目,如果控制台列印以下數據,說明配置成功:

2019-09-21 19:47:25 [sentinel-dashboard-metrics-fetchWorker-thread-2] INFO  okhttp3.OkHttpClient - --> POST http://118.190.247.102:8086/write?db=sentinel_log&precision=n&consistency=all (486-byte body)  2019-09-21 19:47:25 [sentinel-dashboard-metrics-fetchWorker-thread-2] INFO  okhttp3.OkHttpClient - <-- 204 No Content http://118.190.247.102:8086/write?db=sentinel_log&precision=n&consistency=all (46ms, 0-byte body)  

多訪問幾次客戶端項目,然後登陸控制台查看,出現以下效果,說明改造成功:

注意事項:

  • 官方前端並沒有實現按照時間範圍的查詢搜索,需要自行實現

  • 官方控制台實時監控默認查詢的是最近一分鐘的熱點資源排行,見方法 listResourcesOfApp

  • 官方控制台實時監控右側 Table 默認查詢的是最近五分鐘的熱點訪問詳情,見方法 queryTopResourceMetric

小結

對於官方五分鐘的閹割版,時序資料庫實現的流控數據存儲,對於生產環境還是很有幫助的,比如實時數據分析,熱點資源、監控預警等等。小夥伴們還可以根據實際生產需求結合Chronograf、Grafana 做出更炫酷的大屏監控。

源碼

https://gitee.com/52itstyle/sentinel-dashboard

參考

https://blog.52itstyle.vip/archives/4460/

https://hub.docker.com/_/influxdb

https://hub.docker.com/_/chronograf

https://github.com/influxdata/influxdb-java

https://github.com/influxdata/influxdb-python

https://help.aliyun.com/document_detail/97578.htm

Tags: