一、背景
當項目的各項服務越來越多的時候,監控服務就要開始承擔起越來越多的職責,這時候我們需要收集起各個業務模塊的指標或者是機器的參數,來實時地反饋情況以供我們發現問題或者是做一些調優,比如我們常用的Windows的任務管理器就是這樣類似的道理。
那麼說起監控這些指標的話肯定要用一些變量或者一些公共的類去收集起來,然後通過一些自定義的方式保留接口供別人查詢,或者直接圖形化,Metric的作用就是充當一個度量的作用,即:爲數據的多少、速率、健康與否這些提供一種衡量的標準,說白了,其實不用Metric,你也可以有自己的方法實現比較簡單的數據採集,然後拿出來當監控用。但是我們用Metric的話待會會提到它的一些比較好的設計,可以在同一個應用中隨便一個地方調用同一個類的靜態方法獲取收集過了的數據,這是其一。其二就是當你在一家公司內功能模塊比較多,需要多個開發人員或者小組協助的時候,用同一種度量方式去檢測,好處自然不言而喻。
下面是對Metrics官網的一些筆記,喜歡原汁原味的可以直接拉到文章底部看英文原版嘿嘿。
二、依賴
<dependencies>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
</dependency>
</dependencies>
${metrics.version}可以是3.2.2
三、Registry和其他你該知道的幾個概念
1、Metrics的核心是MetricRegistry
類,
創建的方法:
final MetricRegistry metrics = new MetricRegistry();
一般一個應用用一個實例就夠了,可以使用依賴注入或者static的方式。
2、Metrics當中有很多的度量類,比如Gauages、Counter等等,你可以理解爲:這些可以度量類爲平時大部分的統計方法提供了一種普適性的模型,是上面MetricRegistry
這個大工廠的產品。下面會簡單介紹幾種,後續可以自行去官網多多查閱不同的應用場景適合用什麼度量類。
3、Reporter 簡單理解爲輸出的方式,可以是console、log4j、cvs文件、或者是Ganglia、Graphite等等這樣的視圖工具。
看,其實Metrics監控性能和可用性也和我們平時自己寫的方式差不多。
四、一些度量類
Gauges--最簡單的度量類,返回一個數值。
以下是返回隊列的數量:
public class QueueManager {
private final Queue queue;
public QueueManager(MetricRegistry metrics, String name) {
this.queue = new Queue();
metrics.register(MetricRegistry.name(QueueManager.class, name, "size"),
new Gauge<Integer>() {
@Override
public Integer getValue() {
return queue.size();
}
});
}
}
Meters--速率,衡量一段時間內的數量
private final MetricRegistry metrics = new MetricRegistry();
private final Meter requests = metrics.meter("requests");
public void handleRequest(Request request, Response response) {
requests.mark();
// etc
}
以上代碼表示度量每一秒處理的請求數這一速率。Counters--爲AtomicLong類的實例而生的一個gauge,可以隨意地加減
另外我們都知道AtomicLong
是爲了解決多線程併發的時候保障正確性用的。
AtomicLong
是爲了解決多線程併發的時候保障正確性用的。以下代碼展示瞭如何度量隊列中的待處理任務數量。
private final Counter pendingJobs = metrics.counter(name(QueueManager.class, "pending-jobs"));
public void addJob(Job job) {
pendingJobs.inc();
queue.offer(job);
}
public Job takeJob() {
pendingJobs.dec();
return queue.take();
}
Histograms--
度量流數據的靜態屬性值,除了最大值、最小值、平均值等等這些常見的數據,還度量中間值、百分比.
以下代碼度量了reponse的bytes長度:
private final Histogram responseSizes = metrics.histogram(name(RequestHandler.class, "response-sizes"));
public void handleRequest(Request request, Response response) {
// etc
responseSizes.update(response.getContent().length);
}
Timers--度量某一段代碼被調用的速率(單位時間內調用次數)以及持續時間分佈,多用在性能監控。
以下代碼度量了每毫秒處理的請求數,以及請求/秒的速率
private final Timer responses = metrics.timer(name(RequestHandler.class, "responses"));
public String handleRequest(Request request, Response response) {
final Timer.Context context = responses.time();
try {
// etc;
return "OK";
} finally {
context.stop();
}
}
Health Checks 健康檢查
Metrics可以用一個叫metrics-healthchec
的東西來集中化檢查你的服務是否正常
首先創建一個 metrics-healthchec 的實例方法是這樣的:
final HealthCheckRegistry healthChecks = new HealthCheckRegistry();
然後實現一個 HealthCheck 的子類:
public class DatabaseHealthCheck extends HealthCheck {
private final Database database;
public DatabaseHealthCheck(Database database) {
this.database = database;
}
@Override
public HealthCheck.Result check() throws Exception {
if (database.isConnected()) {
return HealthCheck.Result.healthy();
} else {
return HealthCheck.Result.unhealthy("Cannot connect to " + database.getUrl());
}
}
}
然後用這個實例向Metrics註冊
healthChecks.register("postgres", new DatabaseHealthCheck(database));
運行所有的健康檢查:
final Map<String, HealthCheck.Result> results = healthChecks.runHealthChecks();
for (Entry<String, HealthCheck.Result> entry : results.entrySet()) {
if (entry.getValue().isHealthy()) {
System.out.println(entry.getKey() + " is healthy");
} else {
System.err.println(entry.getKey() + " is UNHEALTHY: " + entry.getValue().getMessage());
final Throwable e = entry.getValue().getError();
if (e != null) {
e.printStackTrace();
}
}
}
五、Reporter
Console Reporter--將數據反饋到console
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.SECONDS);
Reporting Via JMX--通過JMX的方式報告
final JmxReporter reporter = JmxReporter.forRegistry(registry).build();
reporter.start();
start()之後,所有registry裏面的metrics將在JConsole和VisualVM中可見(如果安裝了MBeans插件)
另外這雙擊任何一個metric屬性的話 VisualVM將會以圖形化數據的形式展示。
其他的Reporting
STDOUT
, 從metrics-core
獲取並使用ConsoleReporterCSV
文件, 從metrics-core
獲取並使用CsvReporter- SLF4J loggers,
從
metrics-core
獲取並使用Slf4jReporter - Ganglia,從
metrics-core
獲取並 使用GangliaReporter - Graphite, 從
metrics-core
獲取並使用GraphiteReporter
六、快速啓動:
package sample;
import com.codahale.metrics.*;
import java.util.concurrent.TimeUnit;
public class GetStarted {
static final MetricRegistry metrics = new MetricRegistry();
public static void main(String args[]) {
startReport();
Meter requests = metrics.meter("requests");
requests.mark();
wait5Seconds();
}
static void startReport() {
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.SECONDS);
}
static void wait5Seconds() {
try {
Thread.sleep(5*1000);
}
catch(InterruptedException e) {}
}
}
資料鏈接
http://metrics.dropwizard.io/3.2.2/getting-started.html
http://metrics.dropwizard.io/3.2.2/manual/core.html#man-core-reporters-slf4j