博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
第三十五章 metrics(3)- codahale-metrics基本使用
阅读量:5091 次
发布时间:2019-06-13

本文共 11488 字,大约阅读时间需要 38 分钟。

1         
2
3
io.dropwizard.metrics
4
metrics-core
5
View Code

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

一、meter类metrics

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

例如:qps

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

1 package com.xxx.secondboot.metrics; 2  3 import java.util.concurrent.TimeUnit; 4  5 import com.codahale.metrics.ConsoleReporter; 6 import com.codahale.metrics.Meter; 7 import com.codahale.metrics.MetricRegistry; 8  9 /**10  * Meter11  * 作用:度量速率(例如,tps)12  * Meters会统计最近1分钟(m1),5分钟(m5),15分钟(m15),还有全部时间的速率(速率就是平均值)。13  */14 public class TestMeter {15     public static void main(String[] args) throws InterruptedException {16         final MetricRegistry registry = new MetricRegistry();//其实就是一个metrics容器,因为该类的一个属性final ConcurrentMap
metrics,在实际使用中做成单例就好17 ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)18 .convertRatesTo(TimeUnit.SECONDS)19 .convertDurationsTo(TimeUnit.MILLISECONDS)20 .build();21 reporter.start(1, TimeUnit.SECONDS);//从启动后的1s后开始(所以通常第一个计数都是不准的,从第二个开始会越来越准),每隔一秒从MetricRegistry钟poll一次数据22 Meter meterTps = registry.meter(MetricRegistry.name(TestMeter.class, "request", "tps"));//将该Meter类型的指定name的metric加入到MetricsRegistry中去23 24 System.out.println("执行与业务逻辑");25 26 while(true){27 meterTps.mark();//总数以及m1,m5,m15的数据都+128 Thread.sleep(500);29 }30 }31 }

注意:

  • 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()方法源码:

1     public void start(long period, TimeUnit unit) { 2         executor.scheduleAtFixedRate(new Runnable() { 3             @Override 4             public void run() { 5                 try { 6                     report(); 7                 } catch (RuntimeException ex) { 8                     LOG.error("RuntimeException thrown from {}#report. Exception was suppressed.", ScheduledReporter.this.getClass().getSimpleName(), ex); 9                 }10             }11         }, period, period, unit);12     }
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

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

1 package com.xxx.secondboot.metrics; 2  3 import java.time.LocalDateTime; 4 import java.util.LinkedList; 5 import java.util.Queue; 6 import java.util.concurrent.TimeUnit; 7  8 import com.codahale.metrics.ConsoleReporter; 9 import com.codahale.metrics.Gauge;10 import com.codahale.metrics.MetricRegistry;11 12 /**13  * Gauge14  * 作用:只返回一个简单值(一个瞬时值)15  * eg:返回队列的size16  */17 public class TestGauge {18 19     public static Queue
queue = new LinkedList<>();//队列20 21 public static void main(String[] args) {22 MetricRegistry registry = new MetricRegistry();23 ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)24 .convertRatesTo(TimeUnit.SECONDS)25 .convertDurationsTo(TimeUnit.MILLISECONDS)26 .build();27 reporter.start(1, TimeUnit.SECONDS);28 29 registry.register(MetricRegistry.name(TestGauge.class, "queue", "size"), new Gauge
() {30 public Integer getValue() {31 return queue.size();32 }33 });34 35 while (true) {36 try {37 Thread.sleep(1000);38 queue.add("job - " + LocalDateTime.now());39 } catch (InterruptedException e) {40 e.printStackTrace();41 }42 }43 }44 }

注意:

  • 在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,线程安全

1 package com.xxx.secondboot.metrics; 2  3 import java.util.Queue; 4 import java.util.concurrent.LinkedBlockingQueue; 5 import java.util.concurrent.TimeUnit; 6  7 import com.codahale.metrics.ConsoleReporter; 8 import com.codahale.metrics.Counter; 9 import com.codahale.metrics.MetricRegistry;10 11 /**12  * counter:13  * 作用:计数器(用gauge封装了AtomicLong)14  */15 public class TestCounters {16     public static Queue
queue = new LinkedBlockingQueue<>();17 public static Counter counter;//计算queue的大小18 19 public static void main(String[] args) throws InterruptedException {20 MetricRegistry registry = new MetricRegistry();21 ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)22 .convertRatesTo(TimeUnit.SECONDS)23 .convertDurationsTo(TimeUnit.MILLISECONDS)24 .build();25 reporter.start(1, TimeUnit.SECONDS);26 counter = registry.counter(MetricRegistry.name(TestCounters.class, "queue", "size"));27 28 int num = 0;29 while (true) {30 if (num < 10) {31 queue.add("job - " + num);32 counter.inc();33 } else if (num > 10 && num < 16) {34 queue.poll();35 counter.dec();36 } else {37 queue.add("job - " + num);38 counter.inc();39 }40 num++;41 Thread.sleep(500);42 }43 }44 }

输出:

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的操作需要获取锁,操作之后释放锁。线程安全。

1 package com.xxx.secondboot.metrics; 2  3 import java.util.Random; 4 import java.util.concurrent.TimeUnit; 5  6 import com.codahale.metrics.ConsoleReporter; 7 import com.codahale.metrics.ExponentiallyDecayingReservoir; 8 import com.codahale.metrics.Histogram; 9 import com.codahale.metrics.MetricRegistry;10 11 /**12  * Histogram13  * 作用:计算执行次数count、最小值min,最大值max,平均值mean,方差stddev,中位数median,75百分位, 90百分位, 95百分位, 98百分位, 99百分位, 和 99.9百分位的值14  */15 public class TestHistogram {16     public static void main(String[] args) throws InterruptedException {17         MetricRegistry registry = new MetricRegistry();18         ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)19                 .convertRatesTo(TimeUnit.SECONDS)20                 .convertDurationsTo(TimeUnit.MILLISECONDS)21                 .build();22         reporter.start(1, TimeUnit.SECONDS);23         24         Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir());//95%25         registry.register(MetricRegistry.name(TestHistogram.class, "request","histogram"), histogram);26         27         Random random = new Random();28         while(true){29             Thread.sleep(1000);30             histogram.update(random.nextInt(10000));31         }32     }33 }

输出:

1 16-10-3 21:26:05 =============================================================== 2  3 -- Histograms ------------------------------------------------------------------ 4 com.xxx.secondboot.metrics.TestHistogram.request.histogram 5              count = 3 6                min = 685 7                max = 6754 8               mean = 3149.05 9             stddev = 2584.3610             median = 2078.0011               75% <= 6754.0012               95% <= 6754.0013               98% <= 6754.0014               99% <= 6754.0015             99.9% <= 6754.00

 

五、timer类metrics

作用:meter和histogram的组合体

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

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

1 package com.xxx.secondboot.metrics; 2  3 import java.util.concurrent.TimeUnit; 4  5 import com.codahale.metrics.ConsoleReporter; 6 import com.codahale.metrics.MetricRegistry; 7 import com.codahale.metrics.Timer; 8  9 /**10  * Timers11  * 作用:histogram和meter的组合体12  */13 public class TestTimer {14     public static void main(String[] args) throws InterruptedException {15         MetricRegistry registry = new MetricRegistry();16         ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();17         reporter.start(1, TimeUnit.SECONDS);18         19         Timer timer = registry.timer(MetricRegistry.name(TestTimer.class, "get-latency"));20         Timer.Context ctx = timer.time();21         22         try{23             Thread.sleep(2000);24         }finally{25             ctx.stop();26         }27     }28 }

输出:

1 -- Timers ---------------------------------------------------------------------- 2 com.xxx.secondboot.metrics.TestTimer.get-latency 3              count = 0 4          mean rate = 0.00 calls/second 5      1-minute rate = 0.00 calls/second 6      5-minute rate = 0.00 calls/second 7     15-minute rate = 0.00 calls/second 8                min = 0.00 milliseconds 9                max = 0.00 milliseconds10               mean = 0.00 milliseconds11             stddev = 0.00 milliseconds12             median = 0.00 milliseconds13               75% <= 0.00 milliseconds14               95% <= 0.00 milliseconds15               98% <= 0.00 milliseconds16               99% <= 0.00 milliseconds17             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/

转载于:https://www.cnblogs.com/java-zhao/p/5929723.html

你可能感兴趣的文章
查看hive的配置信息
查看>>
获取局域网中指定IP或是主机名称的所有文件夹及其搜索文件
查看>>
Hibernate 多对一连接表单向关联
查看>>
java 24 - 6 GUI之 创建只能输入数字的文本框
查看>>
Noip2017游记
查看>>
接口访问权限
查看>>
如何判断一个form是否被关闭
查看>>
Python 网页爬虫
查看>>
5-8 彩色直方图均衡化
查看>>
C语言结合汇编开发系统内核
查看>>
第十章 优先级队列 (xa1)左式堆:结构
查看>>
WordPress主机
查看>>
Mysql事务隔离级别详解
查看>>
HDU-Pattern and Text 枚举
查看>>
RPM基础知识
查看>>
docker+gitlab的安装和迁移
查看>>
P3232 [HNOI2013]游走 解题报告
查看>>
Spring 事务相关点整理
查看>>
HDU 2546 饭卡
查看>>
如何将字符串常量转为变量?
查看>>