背景
我們的網關採用了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指標,如果有額外的需求,還可以通過HystrixCommandMetrics
、HystrixCollapserMetrics
來獲取其他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的線程執行指標,也可以是各類業務指標。總之,最終目的就是希望通過可視化的界面,來快速掌握分析應用的運行狀況,來進行實時監控乃至後續的優化,希望這篇文章能幫到你。