欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Metric的快速入门

程序员文章站 2022-05-23 23:22:14
...

一、背景

   当项目的各项服务越来越多的时候,监控服务就要开始承担起越来越多的职责,这时候我们需要收集起各个业务模块的指标或者是机器的参数,来实时地反馈情况以供我们发现问题或者是做一些调优,比如我们常用的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是为了解决多线程并发的时候保障正确性用的。

以下代码展示了如何度量队列中的待处理任务数量。

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的快速入门

另外这双击任何一个metric属性的话 VisualVM将会以图形化数据的形式展示。

其他的Reporting

六、快速启动:

 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