之前介紹了Sentinel相關的文章,小伙伴在生產實踐中不知道有沒有這個疑問?我們的Sentinel控制台監控的數據只能看最近5分鍾的,如圖
那么就導致歷史數據是查看不了的,那肯定是不行的,在生產環境中我們最起碼能夠看到最近幾天甚至幾個月的監控數據,方便我們排查出哪些時間段/哪些天,哪些接口會到達什么樣的QPS;方便我們對整體系統的QPS、以及異常情況有基本的了解。
如果要做到這些,就需要做到對這些數據進行持久化,而不能只保存在內存中。那我們今天就來介紹一下怎么改造Sentinel控制台,可以達到持久化的目的。同時用XMind畫了一張導圖記錄Spring Cloud Alibaba的學習筆記(源文件對部分節點有詳細備注和參考資料,由於太大就沒展示全部,歡迎關注我的公眾號:阿風的架構筆記 后台發送【導圖】拿下載鏈接, 已經完善更新):
分析
Sentinel客戶端會記錄資源訪問的秒級數據(若沒有訪問則不進行記錄)並保存在本地日志中。Sentinel 控制台可以通過 Sentinel 客戶端預留的 HTTP API 從秒級監控日志中拉取監控數據,並進行聚合。
目前Sentinel控制台中監控數據聚合后直接存在內存中,未進行持久化,且僅保留最近 5 分鍾的監控數據。核心思想就是實現MetricsRepository接口實現,源碼如下
MetricsRepository定義了以下接口:
save 與 saveAll:存儲對應的監控數據
queryByAppAndResourceBetween:查詢某段時間內的某個應用的某個資源的監控數據
listResourcesOfApp:查詢某個應用下的所有資源
現在Sentinel控制台只實現了內存InMemoryMetricsRepository,接口可傳入自定義范型
上面默認的監控數據類型為MetricEntity,包含應用名稱、時間戳、資源名稱、異常數、請求通過數、請求拒絕數、平均響應時間等信息。
對於監控數據的存儲,用戶需要根據自己的存儲精度,來考慮如何存儲這些監控數據。部署多個控制台實例時,通常需要仔細設計下監控拉取和寫入策略。
我們知道了Sentinel的實現,那我們持久化監控的方案是什么呢?
方案
我們把監控數據持久化到哪里呢?能想到的就是數據庫,但不要選擇mysql數據庫,而是選擇帶時序功能的數據庫方案,可采用主流的InfluxDB時序數據庫
具體InfluxDB和mysql有什么區別,可網上查看
持久化是第一步,我們下一步還需要用圖表的方式展現出來,我們第一個能夠想到的方案就是Grafana。
小伙伴如果不了解,自行網補
這樣我們具體的方案就有了,如圖
代碼
現在Sentinel控制台項目pom.xml中引入influxdb包
<dependency>
<groupId>org.influxdb</groupId>
<artifactId>influxdb-java</artifactId>
<version>2.21</version>
</dependency>
封裝一個influxdb工具類
- url、username、password用於存儲InfluxDB的連接、用戶名、密碼信息,定義為static屬性,因此在set方法上使用@Value注解從配置文件讀取屬性值;
- resultMapper用於查詢結果到實體類的映射;
- init方法用於初始化url、username、password;
- process為通用的處理方法,負責打開關閉連接,並且調用InfluxDBCallback回調方法;
- insert為插入數據方法,配合InfluxDBInsertCallback回調使用;
- query為通用的查詢方法,配合InfluxDBQueryCallback回調方法使用,返回QueryResult對象;
- queryList為查詢列表方法,調用query得到QueryResult,再通過resultMapper轉換為List<實體類>;
**在resources目錄下的application.properties文件中,增加InfluxDB的配置: **
influxdb.url=http://127.0.0.1:8086
influxdb.username=admin
influxdb.password=admin
在datasource.entity包下,新建influxdb包,下面新建sentinel_metric數據表(measurement)對應的實體類MetricPO:
該類參考MetricEntity創建,加上influxdb-java包提供的注解
通過@Measurement(name = "sentinel_metric")指定數據表(measurement)名稱
time作為時序數據庫的時間列;
app、resource設置為tag列,通過注解標識為tag=true;
其它字段為filed列;
接着在InMemoryMetricsRepository所在的repository.metric包下新建InfluxDBMetricsRepository類,實現MetricsRepository
其中:
- save、saveAll方法通過調用InfluxDBUtils.insert和InfluxDBInsertCallback回調方法,往sentinel_db庫的sentinel_metric數據表寫數據;
- saveAll方法不是循環調用save方法,而是在回調內部循環Iterable
metrics處理,這樣InfluxDBFactory.connect連接只打開關閉一次; - doSave方法中,.time(DateUtils.addHours(metric.getTimestamp(), 8).getTime(), TimeUnit.MILLISECONDS)
- queryByAppAndResourceBetween、listResourcesOfApp里面的查詢方法,使用InfluxDB提供的類sql語法,編寫查詢語句即可。
最后一步,在MetricController、MetricFetcher兩個類,找到metricStore屬性,
在@Autowired注解上面加上@Qualifier("influxDBMetricsRepository")注解:
到此持久化就完成了,可以啟動測試一下,就可以發現influxdb進入了監控數據
監控
部署安裝Grafana這里就不介紹了,自行網補;Grafana有模板的概念,只要配置了模板,然后動態傳入參數即可快速生成多個使用相同模板的不同指標數據的圖表。
添加模板
然后配置SQL執行查詢,即時可看到效果
配置好以后使用模板功能查看多個接口的流控指標監控
具體Grafana配置,小伙伴們可以自行網補
方案優化
上面我們已經實現了監控數據持久化到influxDB中了,但是我們會發現一寫問題
1、sentinel-dashboard目前是每隔一秒從所有的客戶端同步一次數據, 集群龐大的情況下,控制台需要拉取很多客戶端的數據,效率很低且不穩定,看源碼
2、sentinel-dashboard收集到數據以后直接插入數據庫沒有緩沖,吞吐量低,性能低
基於上面的問題我們可以優化一下方案
優化方案
優化點
-
增加一個服務Sentinel Server,用來就是收集監控數據
-
Sentinel客戶端主動推送給Sentinel Server,不需要去拉;這樣就解決了集群大的情況
-
增加kafka消息中間件,做了數據的緩沖,性能以及吞吐量會大大提升
-
Sentinel Server發布以及訂閱監控數據消息
這個優化方案就要把Sentinel控制台中的監控業務移除掉
總結
這篇文章最主要解決了監控數據持久化監控的問題,涉及到最終的優化方案有時間后續文章介紹,希望這篇文章能夠幫助小伙伴們,謝謝!!!
看完三件事❤️
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
- 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
- 關注公眾號 『 阿風的架構筆記 』,不定期分享原創知識。
- 同時可以期待后續文章ing🚀
- 關注后回復【666】掃碼即可獲取架構進階學習資料包