打造可监控的线上应用dropwizard-metrics

来源:互联网 发布:航悦淘宝上的冰冰精华 编辑:程序博客网 时间:2024/05/17 00:49

dropwizard-metrics

Metrics is a Java library which gives you unparalleled insight into what your code does in production.
Metrics provides a powerful toolkit of ways to measure the behavior of critical components in your production environment.

Getting Started

Setting Up Maven

<dependencies>    <dependency>        <groupId>io.dropwizard.metrics</groupId>        <artifactId>metrics-core</artifactId>        <version>${metrics.version}</version>    </dependency></dependencies>

核心组件:MetricRegistry 及核心方法

这样实例化:

final MetricRegistry metrics = new MetricRegistry();

方法签名:
public T register(String name, T metric) throws IllegalArgumentException {…}

注册一个统计量Gauge

举例,要监测一个队列的长度,每次获取该统计量时返回队列长度:

package org.lanqiao.metrics.test;import com.codahale.metrics.ConsoleReporter;import com.codahale.metrics.Gauge;import com.codahale.metrics.MetricRegistry;import org.web2017.test.data.RandomData;import java.util.LinkedList;import java.util.Queue;import java.util.concurrent.TimeUnit;public class MetricRegistryTest {  // 统计量注册表  final static MetricRegistry metricRegistry = new MetricRegistry();  final static Queue queue = new LinkedList();  public static void main(String[] args) {    //模拟填充队列    new Thread( () -> {      while (true) {        queue.add( RandomData.randomId() );        try {          TimeUnit.SECONDS.sleep( 3 );        } catch (InterruptedException e) {          e.printStackTrace();        }      }    } ).start();    //注册一个Gauge    metricRegistry.register( MetricRegistry.name( MetricRegistryTest.class, "queue","size" ), new Gauge<Integer>() {      @Override      public Integer getValue() {        return queue.size();      }    } );    //向控制台输出报告    //定义一个ConsoleReporter    ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)        .convertRatesTo(TimeUnit.SECONDS)        .convertDurationsTo(TimeUnit.MILLISECONDS)        .build();    reporter.start(1, TimeUnit.SECONDS);  }}

每隔1秒钟输出metricRegistry中的统计量

-- Gauges ----------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest.queue.size             value = 317-10-6 23:48:00 ===============================================================-- Gauges ----------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest.queue.size             value = 317-10-6 23:48:01 ===============================================================-- Gauges ----------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest.queue.size             value = 317-10-6 23:48:02 ===============================================================-- Gauges ----------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest.queue.size             value = 4

注意性能!!此处仅用法举例。

注册一个计数器 Counter

Counter本质是Gauge的AtomicLong版本。

我们可以在某些数量变化的地方对Counter进行加和减。

例如,我们想对方法调用次数做一个统计:

package org.lanqiao.metrics.test;import com.codahale.metrics.ConsoleReporter;import com.codahale.metrics.Counter;import com.codahale.metrics.MetricRegistry;import java.util.concurrent.TimeUnit;public class MetricRegistryTest2 {  // 统计量注册表  final static MetricRegistry metricRegistry = new MetricRegistry();  final static Counter methodInvokeCounter =  metricRegistry.register(      MetricRegistry.name( MetricRegistryTest2.class, "someMethod", "invokeCount" ),      new Counter() );  public static void someMethod() {    methodInvokeCounter.inc();  }  public static void main(String[] args) {    //模拟方法调用    new Thread( () -> {      while (true) {        someMethod();        try {          TimeUnit.SECONDS.sleep( 3 );        } catch (InterruptedException e) {          e.printStackTrace();        }      }    } ).start();    //向控制台输出报告    //定义一个ConsoleReporter    ConsoleReporter reporter = ConsoleReporter.forRegistry( metricRegistry )        .convertRatesTo( TimeUnit.SECONDS )        .convertDurationsTo( TimeUnit.MILLISECONDS )        .build();    reporter.start( 1, TimeUnit.SECONDS );  }}

输出效果:

17-10-6 23:58:05 ===============================================================-- Counters --------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest2.someMethod.invokeCount             count = 417-10-6 23:58:06 ===============================================================-- Counters --------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest2.someMethod.invokeCount             count = 4

关注时间Timer

如果我们对某个方法的执行时间感兴趣,可以这样做:

  final static Timer methodTiming = metricRegistry.timer(      MetricRegistry.name( MetricRegistryTest2.class, "someMethod", "timing" )  );  public static void someMethod() {    //计时    Timer.Context context = methodTiming.time();    methodInvokeCounter.inc();    //结束    context.stop();  }

输出结果如下:

-- Counters --------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest2.someMethod.invokeCount             count = 3-- Timers ----------------------------------------------------------------------org.lanqiao.metrics.test.MetricRegistryTest2.someMethod.timing             count = 3         mean rate = 0.46 calls/second     1-minute rate = 0.40 calls/second     5-minute rate = 0.40 calls/second    15-minute rate = 0.40 calls/second               min = 0.02 milliseconds               max = 0.05 milliseconds              mean = 0.03 milliseconds            stddev = 0.01 milliseconds            median = 0.02 milliseconds              75% <= 0.05 milliseconds              95% <= 0.05 milliseconds              98% <= 0.05 milliseconds              99% <= 0.05 milliseconds            99.9% <= 0.05 milliseconds

设计并呈现健康度Health Checks

首先需要一个HealthCheckRegistry 实例:

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());        }    }}

注册:

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 comes with a pre-built health check: ThreadDeadlockHealthCheck, which uses Java’s built-in thread deadlock detection to determine if any threads are deadlocked.

懒得翻译了,自己看吧。

小结

本文只是dropwizard的metrics的一小部分。

重点示范如何使用MetricRegistry注册各种关注的统计量,以及如何配合ConsoleReporter来定时输出统计结果。

文中示范的统计量有Gauge、Counter和Timer,分别用于统计简单数值,可动态操作数值和运行时间。

另外,示范(从官方抄)了健康检查与结果输出。

ConsoleReporter只是众多Reporter中的一种。

以后(不知道什么时候)我们再介绍JmxReporter。

原创粉丝点击