<!-- metrics -->
         <dependency>
             <groupId>io.dropwizard.metrics</groupId>
             <artifactId>metrics-core</artifactId>
         </dependency>

这里,依托于springboot,版本号是3.1.2

一、meter类metrics

作用:统计最近1分钟(m1),5分钟(m5),15分钟(m15),还有全部时间的速率(速率就是平均值)

例如:qps

线程安全:mark()方法中的四个操作都是基于CAS实现,统计线程安全。

package com.xxx.secondboot.metrics;

import java.util.concurrent.TimeUnit;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;

/**
 * Meter
 * 作用:度量速率(例如,tps)
 * Meters会统计最近1分钟(m1),5分钟(m5),15分钟(m15),还有全部时间的速率(速率就是平均值)。
 */
public class TestMeter {
    public static void main(String[] args) throws InterruptedException {
        final MetricRegistry registry = new MetricRegistry();//其实就是一个metrics容器,因为该类的一个属性final ConcurrentMap<String, Metric> metrics,在实际使用中做成单例就好
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
                                  .convertRatesTo(TimeUnit.SECONDS)
                                  .convertDurationsTo(TimeUnit.MILLISECONDS)
                                  .build();
        reporter.start(1, TimeUnit.SECONDS);//从启动后的1s后开始(所以通常第一个计数都是不准的,从第二个开始会越来越准),每隔一秒从MetricRegistry钟poll一次数据
        Meter meterTps = registry.meter(MetricRegistry.name(TestMeter.class, "request", "tps"));//将该Meter类型的指定name的metric加入到MetricsRegistry中去

        System.out.println("执行与业务逻辑");

        while(true){
            meterTps.mark();//总数以及m1,m5,m15的数据都+1
            Thread.sleep(500);
        }
    }
}

注意:

  • MetricRegistry是一个所有metrics的容器(通常设为单例)
  • ConsoleReporter根据指定的打印速率(在start方法中指定)将metrics打印到console
  • metrics name需要指定,这对于在statsd的统计部分以及聚合函数的选择都有用,上边的name()方法实际上是将类的全类名与后续的不定参数以"."拼接而成,这里metric name就是"com.xxx.secondboot.metrics.TestMeter.request.tps"
  • mark方法:总数count和m1,m5,m15的数据都+1

report.start()方法源码:

public void start(long period, TimeUnit unit) {
        executor.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                try {
                    report();
                } catch (RuntimeException ex) {
                    LOG.error("RuntimeException thrown from {}#report. Exception was suppressed.", ScheduledReporter.this.getClass().getSimpleName(), ex);
                }
            }
        }, period, period, unit);
    }
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

方法含义:

  • 在服务启动的initialDelay unit(这里就是1s)后开始每隔period unit执行一次command(所以,通常第一次统计都不准确,从第二次开始变得准确)
  • reporter值主动从MetricRegistry中poll数据的
  • 真正的report是被synchronized块包起来的(也就是线程安全的),而report的内部逻辑随着report的类型不同而不同(例如,ConsoleReporter就是将四种数据打印到console)

启动服务,输出:(从系统时间开始输出,该例子正好是在01s开始输出的)

16-10-3 20:23:07 ===============================================================

-- Meters ----------------------------------------------------------------------
com.xxx.secondboot.metrics.TestMeter.request.tps
             count = 14
         mean rate = 2.00 events/second
     1-minute rate = 2.00 events/second
     5-minute rate = 2.00 events/second
    15-minute rate = 2.00 events/second

7s内输出14,每秒count+2,符合程序!!!

二、gauge类metrics

作用:返回一个瞬时值(就是一个具体值)

例如:某一时刻的队列size

线程安全:只是做读操作,线程安全

package com.xxx.secondboot.metrics;

import java.time.LocalDateTime;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.MetricRegistry;

/**
 * Gauge
 * 作用:只返回一个简单值(一个瞬时值)
 * eg:返回队列的size
 */
public class TestGauge {

    public static Queue<String> queue = new LinkedList<>();//队列

    public static void main(String[] args) {
        MetricRegistry registry = new MetricRegistry();
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);

        registry.register(MetricRegistry.name(TestGauge.class, "queue", "size"), new Gauge<Integer>() {
            public Integer getValue() {
                return queue.size();
            }
        });

        while (true) {
            try {
                Thread.sleep(1000);
                queue.add("job - " + LocalDateTime.now());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

注意:

  • 在registry()的时候,可以直接将一个类型的Metric直接注入到容器中,其name就是registry()的第一个参数

输出:

16-10-3 20:57:27 ===============================================================

-- Gauges ----------------------------------------------------------------------
com.xxx.secondboot.metrics.TestGauge.queue.size
             value = 1

三、counter类metrics

作用:gauge的AtomicLong实例(Counter 只是用 Gauge 封装了 AtomicLong),可用于加(inc())减(dec())

例如:获得队列长度(此处的获取要比使用gauge通过size()方法获取高效很多,后者size()方法的获取大多数是O(n)),方法执行成功失败次数(这个就是gauge无法做的)

作用:AtomicLong基于CAS,线程安全

package com.xxx.secondboot.metrics;

import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Counter;
import com.codahale.metrics.MetricRegistry;

/**
 * counter:
 * 作用:计数器(用gauge封装了AtomicLong)
 */
public class TestCounters {
    public static Queue<String> queue = new LinkedBlockingQueue<>();
    public static Counter       counter;//计算queue的大小

    public static void main(String[] args) throws InterruptedException {
        MetricRegistry registry = new MetricRegistry();
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);
        counter = registry.counter(MetricRegistry.name(TestCounters.class, "queue", "size"));

        int num = 0;
        while (true) {
            if (num < 10) {
                queue.add("job - " + num);
                counter.inc();
            } else if (num > 10 && num < 16) {
                queue.poll();
                counter.dec();
            } else {
                queue.add("job - " + num);
                counter.inc();
            }
            num++;
            Thread.sleep(500);
        }
    }
}

输出:

16-10-3 21:15:17 ===============================================================

-- Counters --------------------------------------------------------------------
com.xxx.secondboot.metrics.TestCounters.queue.size
             count = 4

四、histogram类metrics(使用较少)

作用:计算执行次数count、最小值min,最大值max,平均值mean,方差stddev,中位数median,75百分位, 90百分位, 95百分位, 98百分位, 99百分位, 和 99.9百分位的值

例如:统计某个函数的执行耗时,以上这些值通常会是执行时间,如min是最短执行时间等

线程:update的操作需要获取锁,操作之后释放锁。线程安全。

package com.xxx.secondboot.metrics;

import java.util.Random;
import java.util.concurrent.TimeUnit;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.ExponentiallyDecayingReservoir;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;

/**
 * Histogram
 * 作用:计算执行次数count、最小值min,最大值max,平均值mean,方差stddev,中位数median,75百分位, 90百分位, 95百分位, 98百分位, 99百分位, 和 99.9百分位的值
 */
public class TestHistogram {
    public static void main(String[] args) throws InterruptedException {
        MetricRegistry registry = new MetricRegistry();
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);

        Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir());//95%
        registry.register(MetricRegistry.name(TestHistogram.class, "request","histogram"), histogram);

        Random random = new Random();
        while(true){
            Thread.sleep(1000);
            histogram.update(random.nextInt(10000));
        }
    }
}
16-10-3 21:26:05 ===============================================================

-- Histograms ------------------------------------------------------------------
com.xxx.secondboot.metrics.TestHistogram.request.histogram
             count = 3
               min = 685
               max = 6754
              mean = 3149.05
            stddev = 2584.36
            median = 2078.00
              75% <= 6754.00
              95% <= 6754.00
              98% <= 6754.00
              99% <= 6754.00
            99.9% <= 6754.00

五、timer类metrics

作用:meter和histogram的组合体

例如:统计某个函数的qps和执行耗时。

线程安全:meter和histogram都安全,所以也线程安全

package com.xxx.secondboot.metrics;

import java.util.concurrent.TimeUnit;

import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;

/**
 * Timers
 * 作用:histogram和meter的组合体
 */
public class TestTimer {
    public static void main(String[] args) throws InterruptedException {
        MetricRegistry registry = new MetricRegistry();
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();
        reporter.start(1, TimeUnit.SECONDS);

        Timer timer = registry.timer(MetricRegistry.name(TestTimer.class, "get-latency"));
        Timer.Context ctx = timer.time();

        try{
            Thread.sleep(2000);
        }finally{
            ctx.stop();
        }
    }
}

输出:

-- Timers ----------------------------------------------------------------------
com.xxx.secondboot.metrics.TestTimer.get-latency
             count = 0
         mean rate = 0.00 calls/second
     1-minute rate = 0.00 calls/second
     5-minute rate = 0.00 calls/second
    15-minute rate = 0.00 calls/second
               min = 0.00 milliseconds
               max = 0.00 milliseconds
              mean = 0.00 milliseconds
            stddev = 0.00 milliseconds
            median = 0.00 milliseconds
              75% <= 0.00 milliseconds
              95% <= 0.00 milliseconds
              98% <= 0.00 milliseconds
              99% <= 0.00 milliseconds
            99.9% <= 0.00 milliseconds

总结:

  • 统计某个函数被调用的频率(TPS),使用Meters。
  • 统计某个方法的耗时,使用Histograms。--注意时间是以纳秒为单位的
  • 既要统计某个方法的TPS又要统计其耗时时,使用Timers。--注意时间是以纳秒为单位的
  • counter用于计数
  • gauge只用于记录瞬时值

counter与gauge:

  • 在某些时候,只能用gauge,比如说这个值是在第三方包提供的,例如guava cache的cache size(而恰好我们将该cache集成在spring cache中,通过注解来使用了),无法用哪个counter来测量
  • 在某些时候,只能用counter,比如说一个方法的执行成功与失败次数

histogram:

在统计中位数以及95%这样的数据的时候,通常需要把所有的数据拿出来,然后进行运算(在大量的数据下该方法失效,所以采用了水库采集法--reservoir sampling,通过维护一个小的、可管理的水库来代表全部统计数据),具体采集法有以下几种:

  • Uniform Reservoirs:随机选择具有线性递减概率的储层的值,仅用于长时间的测量。测量统计数据最近是不是发生了变化,不要使用这个(使用下边的指数衰减水库)。
  • Exponentially Decaying Reservoirs(指数衰减水库):该水库采集的数据可以代表大约最后5分钟的全部数据。该水库也是Times 类metrics使用histogram的默认选择水库。
  • Sliding Window Reservoirs:代表过去n次测量的数据
  • Sliding Time Window Reservoirs:严格的代表过去n秒内的数据(注意与指数衰减库的区别,该方法严格的记录过去的每一秒的数据(而指数衰减其实还是在最后5min进行抽样),所以在高频下可能需要更多内存,而且也是最慢的水库类型)

参考:

http://metrics.dropwizard.io/3.1.0/getting-started/

http://wuchong.me/blog/2015/08/01/getting-started-with-metrics/

【第三十五章】 metrics(3)- codahale-metrics基本使用的更多相关文章

  1. Gradle 1.12用户指南翻译——第三十五章. Sonar 插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  2. “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. “全栈2019”Java第三十五章:面向对象

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  4. 第三十五章 metrics(3)- codahale-metrics基本使用

    <!-- metrics --> <dependency> <groupId>io.dropwizard.metrics</groupId> <a ...

  5. SpringBoot | 第三十五章:Mybatis的集成和使用

    前言 最近收到公众号留言说,单纯的Mybatis的集成和使用.前面在第九章:Mybatis-plus的集成和使用介绍了基于mybatis-plus的集成和使用.后者也只是对mybatis进行了功能增强 ...

  6. 【WPF学习】第三十五章 资源字典

    如果希望在多个项目之间共享资源,可创建资源字典.资源字典只是XAML文档,除了存储希望使用的资源外,不做其他任何事情. 一.创建资源字典 下面是一个资源字典示例,它包含一个资源: <Resour ...

  7. 第三十五章 Linux常规练习题(二)参考答案

    一.练习题一 1.删除用户基本组shanghai03.发现无法正常删除,怎样才能将其删除掉,不能删除用户. groupdel shanghai03 移除其所属组的用户 2.打开多个xshell窗口连接 ...

  8. 第三十五章 POSIX共享内存

    POSIX共享内存函数介绍 shm_open 功能: 用来创建或打开一个共享内存对象 原型: int shm_open(const char *name, int oflag, mode_t mode ...

  9. 第三十五章、PyQt输入部件:QFontComboBox、QLineEdit、QTextEdit、QPlainText功能详解

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.引言 输入部件量比较多,且功能很丰富,但除了用于编写编辑器.浏览器 ...

随机推荐

  1. 洛谷P4168 蒲公英 [Violet] 分块

    题解:分块+离散化 解题报告: 一个分块典型题呢qwq还是挺妙的毕竟是道黑题 然,然后发现忘记放链接了先放链接QAQ 有两三种解法,都港下qwq 第一个是O(n5/3)的复杂度,谢总说不够优秀没有港, ...

  2. [python-opencv] 模糊操作

    @不要在奋斗的年纪 选择安逸 均值模糊 中值模糊 自定义模糊 意义与应用场景 模糊的基本原理: 1.基于离散卷积 2.定义好每个卷积核 3.不同卷积核得到不同的卷积效果 4.模糊是卷积的一种表象 #均 ...

  3. PS快速制作下雪效果

    PS快速制作下雪效果 具体的制作步骤如下: 1.打开PS,打开素材,打开窗口-动作 2.创建新动作,参数如下图 3.回到图层,建立一个图层,填充黑色,如下图 4.滤镜-像素化-点状化,参数如下图 5. ...

  4. qt——常用的布局方法

    布局相关对象及简介 窗体上的所有的控件必须有一个合适的尺寸和位置.Qt提供了一些类负责排列窗体上的控件,主要有:QHBoxLayout,QVBoxLayout,QGridLayout,QStackLa ...

  5. 如何使用Soft-NMS实现目标检测并提升准确率

    非极大值抑制(Non-Maximum suppression,NMS)是物体检测流程中重要的组成部分.它首先基于物体检测分数产生检测框,分数高的检测框M被选中,其他与被选中检测框又明显重叠的检测框被抑 ...

  6. HTML5插件

    HTML 助手(插件) 辅助应用程序(helper application)是可由浏览器启动的程序.辅助应用程序也称为插件. 辅助程序可用于播放音频和视频(以及其他).辅助程序是使用 <obje ...

  7. [javascript]编码&i字符串格式化&nput历史记录&清空模态框

    js中编码问题 https://www.haorooms.com/post/js_escape_encodeURIComponent 我在前端js添加时候创建dom时候,有汉字,发现是乱码就研究了下 ...

  8. 5分钟实现集群-NTP时间同步

    环境:VMware-Workstation-12-Pro,Windows-10,CentOS-7.5,Xshell5 NTP基本介绍 NTP(Network TimeProtocol,网络时间协议), ...

  9. 浏览器 extension和plugin的区别[来自知乎]

    "扩展"和"插件",其实都是软件组件的一种形式,Chrome 只不过是把两种类型的组件分别给与了专有名称,一个叫"扩展",另一个叫" ...

  10. [LeetCode] 237. Delete Node in a Linked List_Easy tag: Linked List

    Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...