作者:拔劍少年
簡書地址:http://www.reibang.com/u/dad4d9675892
博客地址:https://it18monkey.github.io
轉(zhuǎn)載請注明出處
Metrics 是一個Java庫脖祈,它讓您對代碼在生產(chǎn)中所做的事情有了無與倫比的洞察力俊扳。
Metrics 提供了一種強大的工具集用于度量生產(chǎn)環(huán)境中關(guān)鍵組件的行為翔冀。
對于常見的庫靴患,如Jetty皂甘、Logback、Log4j谈截、Apache HttpClient台舱、Ehcache、JDBI第岖、Jersey和像Ganglia和Graphite等報告后端难菌,Metrics 提供了全棧的可見性。
metric核心:
主要類:Metric registries.
Metrics 主要有五種度量類型 :Gauges, Counters,Histograms, Meters, and Timers.
匯報方式:JMX, theconsole, CSV files, andSLF4J loggers.
首先蔑滓,我們通過在現(xiàn)有程序中添加Metrics的方式來認識和學(xué)會使用Metrics郊酒。
添加Maven 依賴
<dependencies>
<dependency>
<groupId>io.dropwizard.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>${metrics.version}</version>
</dependency>
</dependencies>
注:metrics.version 填寫最新版本。當前版本3.2.3
Meters
Meter用來測量事件的速率(比如每秒的請求等)键袱,除了平均速率燎窘,Meters也可以追蹤1-5-15分鐘的移(或流、滑)動平均數(shù)
private final MetricRegistry metrics = new MetricRegistry();
private final Meter requests = metrics.meter("requests");
public void handleRequest(Request request, Response response) {
requests.mark();
// etc
}
Meters 將會測量每秒請求的速率蹄咖。
Console Reporter
Console Reporter 顧名思義是用來匯報到控制臺的褐健。下面的示例將會每秒打印一次
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build();
reporter.start(1, TimeUnit.SECONDS);
完整代碼:
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) {}
}
}
Registry
Metrics的中心是MetricRegistry 類,它是你程序中所有metric的容器澜汤。所以程序一開始就創(chuàng)建了一個
static final MetricRegistry metrics = new MetricRegistry();
Gauges
gauge可一用來實時測量一個值蚜迅。舉個例子,我們可能想要測量一個阻塞隊列的大小俊抵。
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();
}
});
}
}
當這個gauge被測量的時候?qū)祷仃犃械拇笮 ?br> 注:對于大多數(shù)隊列或類似隊列的數(shù)據(jù)結(jié)構(gòu)來說谁不,你可能不會想簡單的返回queue.size().因為這個方法的大多數(shù)實現(xiàn)都是O(n)的,哪可能會導(dǎo)致gague變得非常慢(可能還會有鎖問題)
每個注冊的metric都有一個唯一的名稱务蝠,僅僅是一個分隔的字符串像是“things.count”或“com.example.Thing.latency”拍谐。MetriRegistry提供了一個靜態(tài)方法來生成這些名稱烛缔。
MetricRegistry.name(QueueManager.class, "jobs", "size")
它會返回一個類似“com.example.QueueManager.jobs.size”的字符串馏段。
Counters
counter 是gauge的原子級別實現(xiàn)
Histograms
hostogram 度量數(shù)據(jù)流中的值的統(tǒng)計分布轩拨。除了最小值、最大值院喜、平均值等亡蓉,它還測量了中位數(shù)、75喷舀、90砍濒、95、98硫麻、99和99.9%爸邢。
private final Histogram responseSizes = metrics.histogram(name(RequestHandler.class, "response-sizes"));
public void handleRequest(Request request, Response response) {
// etc
responseSizes.update(response.getContent().length);
}
上面的histograms 將會度量響應(yīng)的字節(jié)長度。
Timers
timer 度量特定代碼段的速率和其持續(xù)時間的分布拿愧。
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();
}
}
這個timer 將會度量每個請求的執(zhí)行時間并且提供每秒請求的速率杠河。
Health Checks
metrics 也可以通過metrics-healthchecks模塊集中檢測服務(wù)的健康狀況
首先,創(chuàng)建一個新的HealthCheckRegistry實例:
final HealthCheckRegistry healthChecks = new HealthCheckRegistry();
第二步浇辜,實現(xiàn)一個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());
}
}
}
然后注冊一個實例到之前創(chuàng)建的healthChecks 上券敌。
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();
}
}
}
Metrics 附帶一個預(yù)先構(gòu)建的健康檢查:ThreadDeadlockHealthCheck,它使用Java的內(nèi)置線程死鎖檢測來確定是否有任何線程處于死鎖狀態(tài)柳洋。