前言
阿里巴巴提供的控制台只是用於演示 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