当前位置: 首页 > 工具软件 > Metrics > 使用案例 >

监控工具——Metrics 快速入门

傅兴平
2023-12-01

Metrics 快速入门

关于Metrics更多的内容可以查看 metrics-getting-started

代码地址

因为每个例子涉及代码较多,且包含测试用例,如果都贴到文章中内容过多,所以只贴出了部分代码。全部的代码在这里: https://gitee.com/daifyutils/springboot-samples

此篇文章所属模块为:base-metrics

什么是Metrics

Metrics提供了一个强大的工具包,用于衡量生产环境中关键组件的行为。其提供了一个工具包,让我们可以对服务中的一些行为进行监控和统计。按照官方的说法Metrics为Jetty、Logback、Log4j、Apache HttpClient、Ehcache、JDBI、Jersey等多个开源库提供支持。

Metrics 能做什么

简单的说,我们将各个业务模块的指标或者数据收集起来,设置到Metrics中,然后通过Metrics获取相关的统计结果。其实不用Metrics我们也可以实现相关的数据统计,但是Metrics提供了比较完善的分析方法,我们可以主要关注收集指标的过程。

Metrics支持的内容

Metrics主要的统计内容

类型统计内容
Gauges度量指标,简单的值返回
Counter简单计数器
Histograms直方图格式数据,用来统计输入指标中的值分布
Timers计时器,以直方图格式数据显示指标的时间数据
Meters速率统计,比如TPS

Metrics主要的报告格式

  1. Console
  2. JMX
  3. HTTP
  4. CSV
  5. SLF4J
  6. Ganglia
  7. Graphite

如何引入Metrics

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

使用Metric

新增MetricRegistry

MetricRegistry是Metric用来存放metrics数据的容器

MetricRegistry registry = new MetricRegistry();

添加度量信息

使用对应分析度量的同名方法,将需要添加的度量设置到MetricRegistry中。在设置分析度量的时候需要提供一个名称作为分析度量唯一标识。下面是一个设置counter分析度量的代码

// 创建一个度量
registry = new MetricRegistry();
// 注册一个counter
pendingJobs = registry.counter(MetricRegistry.name(Queue.class,"jobs","size"));

创建一个容器并指定日志输出格式

Metric提供了ConsoleReporter 工具方便我们可以快速的获取分析度量中的内容,这个类MetricBase在下面其他度量的使用示例中也会作为他们基类使用

public class MetricBase {

    public static MetricRegistry registry;

    public static void initMetric(){
        // 创建一个度量
        registry = new MetricRegistry();
        // 注册到控制台中
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();
        // 每5秒输出一次结果
        reporter.start(5, TimeUnit.SECONDS);
    }
}

Counter

计数器,内部使用AtomicLong提供了增加和减少值的方法,用来记录一个值的变化

public class CounterTest extends MetricBase{
    private static Queue<String> queue = new LinkedBlockingQueue<String>();

    private static Counter counter;

    private static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        initMetric();

        // 注册一个counter
        counter = registry.counter(MetricRegistry.name(Queue.class,"jobs","size"));
        int num = 1;
        while(true){
            Thread.sleep(200);
            if (random.nextDouble() > 0.7){
                String job = takeJob();
                System.out.println("take job : "+ job);
            }else{
                String job = "Job-"+num;
                addJob(job);
                System.out.println("add job : "+job);
            }
            num++;
        }
    }

    private static void addJob(String job) {
        counter.inc();
        queue.offer(job);
    }

    private static String takeJob() {
        counter.dec();
        return queue.poll();
    }

}

输出内容

22-5-8 10:37:05 ================================================================

-- Counters --------------------------------------------------------------------
java.util.Queue.jobs.size
             count = 33

返回参数

参数获取方法意义
countcounter.getCount()计数器当前值

Gauges

返回单一值,用来获取某些参数中当前的值,创建时需要实现获取值的方法,对外只提供获取值方法

public class GaugesTest extends MetricBase{

    private static Queue<String> taskList = new LinkedList<String>();

    public static void main(String[] args) throws InterruptedException {
        initMetric();
        Gauge gauge = () -> taskList.size();
        // 注册统计内容
        registry.register(MetricRegistry.name(GaugesTest.class, "queue", "size"),gauge);

        while(true){
            Thread.sleep(1000);
            taskList.add("Job-xxx");
        }
    }
}

输出内容

22-5-8 10:40:02 ================================================================

-- Gauges ----------------------------------------------------------------------
dai.samples.metrics.GaugesTest.queue.size
             value = 9

返回参数

参数获取方法意义
countgauge.getValue()计数器当前值

Histogram

直方图格式数据,用来统计输入指标中的值分布,提供最小、最大等参数外还提供了75百分位到99百分位、99.9百分位的值

public class HistogramsTest extends MetricBase{

    public static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        initMetric();
        // 注册一个Histogram,ExponentiallyDecayingReservoir 直方图的统计方式
        Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir());
        registry.register(MetricRegistry.name(HistogramsTest.class, "request", "histogram"), histogram);

        while(true){
            Thread.sleep(1000);
            histogram.update(random.nextInt(100000));
        }
    }
}

输出内容

-- Histograms ------------------------------------------------------------------
dai.samples.metrics.HistogramsTest.request.histogram
             count = 49
               min = 4177
               max = 99701
              mean = 50089.35
            stddev = 31115.63
            median = 39422.00
              75% <= 83459.00
              95% <= 97734.00
              98% <= 97825.00
              99% <= 99701.00
            99.9% <= 99701.00

返回参数

参数获取方法意义
counthistogram.getCount();输入指标总数
minhistogram.getSnapshot().getMin();输入指标最小值
maxhistogram.getSnapshot().getMax();输入指标最大值
meanhistogram.getSnapshot().getMean();输入指标平均值
stddevhistogram.getSnapshot().getStdDev();输入指标中值的标准偏差
medianhistogram.getSnapshot().getMedian();输入指标中位数
75%histogram.getSnapshot().get75thPercentile();输入指标75百分位
95%histogram.getSnapshot().get95thPercentile();输入指标95百分位
98%histogram.getSnapshot().get98thPercentile();输入指标98百分位
99%histogram.getSnapshot().get99thPercentile();输入指标99百分位
99.9%histogram.getSnapshot().get999thPercentile();输入指标99.9百分位

Meters

速率统计,比如TPS。Meters会统计最近1分钟,5分钟,15分钟,还有全部时间的速率。

public class MetersTest extends MetricBase{

    private static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        initMetric();
        Meter meterTps = registry.meter(MetricRegistry.name(MetersTest.class,"request","tps"));

        while(true){
            request(meterTps,random.nextInt(5));
            Thread.sleep(1000);
        }
    }

    private static void request(Meter meter, int n){
        while(n > 0){
            System.out.println("request");
            meter.mark();
            n--;
        }
    }

}

输出内容

-- Meters ----------------------------------------------------------------------
dai.samples.metrics.MetersTest.request.tps
             count = 17
         mean rate = 1.70 events/second
     1-minute rate = 1.62 events/second
     5-minute rate = 1.60 events/second
    15-minute rate = 1.60 events/second

返回参数

参数获取方法意义
countgauge.getValue()计数器当前值
mean ratemeterTps.getMeanRate()平均TPS
1-minute ratemeterTps.getOneMinuteRate()最近1分钟TPS
5-minute ratemeterTps.getFiveMinuteRate()最近5分钟TPS
15-minute ratemeterTps.getFifteenMinuteRate()最近15分钟TPS

Timers

计时器,以直方图格式数据显示指标的时间数据,比如某些操作的耗时等,同时也支持显示Meters的数据分析

public class TimersTest extends MetricBase{

    public static Random random = new Random();

    public static void main(String[] args) throws InterruptedException {
        initMetric();
        Timer timer = registry.timer(MetricRegistry.name(TimersTest.class,"get-latency"));

        Timer.Context ctx;

        while(true){
            ctx = timer.time();
            Thread.sleep(random.nextInt(1000));
            ctx.stop();
        }
    }
}

输出内容

22-5-8 11:42:09 ================================================================

-- Timers ----------------------------------------------------------------------
dai.samples.metrics.TimersTest.get-latency
             count = 41
         mean rate = 2.05 calls/second
     1-minute rate = 2.82 calls/second
     5-minute rate = 2.96 calls/second
    15-minute rate = 2.99 calls/second
               min = 4.47 milliseconds
               max = 905.26 milliseconds
              mean = 480.30 milliseconds
            stddev = 270.88 milliseconds
            median = 536.26 milliseconds
              75% <= 676.99 milliseconds
              95% <= 871.15 milliseconds
              98% <= 905.26 milliseconds
              99% <= 905.26 milliseconds
            99.9% <= 905.26 milliseconds

返回参数

参数获取方法意义
countgauge.getValue()计数器当前值
mean ratetimer.getMeanRate()平均TPS
1-minute ratetimer.getOneMinuteRate()最近1分钟TPS
5-minute ratetimer.getFiveMinuteRate()最近5分钟TPS
15-minute ratetimer.getFifteenMinuteRate()最近15分钟TPS
mintimer.getSnapshot().getMin();输入时间指标最小值
maxtimer.getSnapshot().getMax();输入时间指标最大值
meantimer.getSnapshot().getMean();输入时间指标平均值
stddevtimer.getSnapshot().getStdDev();输入时间指标中值的标准偏差
mediantimer.getSnapshot().getMedian();输入时间指标中位数
75%timer.getSnapshot().get75thPercentile();输入时间指标75百分位
95%timer.getSnapshot().get95thPercentile();输入时间指标95百分位
98%timer.getSnapshot().get98thPercentile();输入时间指标98百分位
99%timer.getSnapshot().get99thPercentile();输入时间指标99百分位
99.9%timer.getSnapshot().get999thPercentile();输入时间指标99.9百分位
 类似资料: