天天看點

SpringBoot 2.0 + InfluxDB+ Sentinel 實時監控資料存儲

SpringBoot 2.0 + InfluxDB+ Sentinel 實時監控資料存儲

前言

阿裡巴巴提供的控制台隻是用于示範 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)
           

多通路幾次用戶端項目,然後登陸控制台檢視,出現以下效果,說明改造成功:

SpringBoot 2.0 + InfluxDB+ Sentinel 實時監控資料存儲

注意事項:

  • 官方前端并沒有實作按照時間範圍的查詢搜尋,需要自行實作
  • 官方控制台實時監控預設查詢的是最近一分鐘的熱點資源排行,見方法

    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