接上《Metrics-Java版的指标度量工具之一》
4. Histograms
Histograms主要使用来统计数据的分布情况,最大值、最小值、平均值、中位数,百分比(75%、90%、95%、98%、99%和99.9%)。例如,需要统计某个页面的请求响应时间分布情况,可以使用该种类型的Metrics进行统计。具体的样例代码如下:
package com.netease.test.metrics; import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.Histogram; import com.codahale.metrics.MetricRegistry; import java.util.Random; import java.util.concurrent.TimeUnit; import static com.codahale.metrics.MetricRegistry.name; /** * User: hzwangxx * Date: 14-2-17 * Time: 18:34 * 测试Histograms */ public class TestHistograms { /** * 实例化一个registry,最核心的一个模块,相当于一个应用程序的metrics系统的容器,维护一个Map */ private static final MetricRegistry metrics = new MetricRegistry(); /** * 在控制台上打印输出 */ private static ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).build(); /** * 实例化一个Histograms */ private static final Histogram randomNums = metrics.histogram(name(TestHistograms.class, "random")); public static void handleRequest(double random) { randomNums.update((int) (random*100)); } public static void main(String[] args) throws InterruptedException { reporter.start(3, TimeUnit.SECONDS); Random rand = new Random(); while(true){ handleRequest(rand.nextDouble()); Thread.sleep(100); } } } /* 14-2-17 19:39:11 =============================================================== -- Histograms ------------------------------------------------------------------ com.netease.test.metrics.TestHistograms.random count = 30 min = 1 max = 97 mean = 45.93 stddev = 29.12 median = 39.50 75% <= 71.00 95% <= 95.90 98% <= 97.00 99% <= 97.00 99.9% <= 97.00 14-2-17 19:39:14 =============================================================== -- Histograms ------------------------------------------------------------------ com.netease.test.metrics.TestHistograms.random count = 60 min = 0 max = 97 mean = 41.17 stddev = 28.60 median = 34.50 75% <= 69.75 95% <= 92.90 98% <= 96.56 99% <= 97.00 99.9% <= 97.00 14-2-17 19:39:17 =============================================================== -- Histograms ------------------------------------------------------------------ com.netease.test.metrics.TestHistograms.random count = 90 min = 0 max = 97 mean = 44.67 stddev = 28.47 median = 43.00 75% <= 71.00 95% <= 91.90 98% <= 96.18 99% <= 97.00 99.9% <= 97.00 */
5. Timers
Timers主要是用来统计某一块代码段的执行时间以及其分布情况,具体是基于Histograms和Meters来实现的。样例代码如下:
package com.netease.test.metrics; import com.codahale.metrics.ConsoleReporter; import com.codahale.metrics.MetricRegistry; import com.codahale.metrics.Timer; import java.util.Random; import java.util.concurrent.TimeUnit; import static com.codahale.metrics.MetricRegistry.name; /** * User: hzwangxx * Date: 14-2-17 * Time: 18:34 * 测试Timers */ public class TestTimers { /** * 实例化一个registry,最核心的一个模块,相当于一个应用程序的metrics系统的容器,维护一个Map */ private static final MetricRegistry metrics = new MetricRegistry(); /** * 在控制台上打印输出 */ private static ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).build(); /** * 实例化一个Meter */ // private static final Timer requests = metrics.timer(name(TestTimers.class, "request")); private static final Timer requests = metrics.timer(name(TestTimers.class, "request")); public static void handleRequest(int sleep) { Timer.Context context = requests.time(); try { //some operator Thread.sleep(sleep); } catch (InterruptedException e) { e.printStackTrace(); } finally { context.stop(); } } public static void main(String[] args) throws InterruptedException { reporter.start(3, TimeUnit.SECONDS); Random random = new Random(); while(true){ handleRequest(random.nextInt(1000)); } } } /* 14-2-18 9:31:54 ================================================================ -- Timers ---------------------------------------------------------------------- com.netease.test.metrics.TestTimers.request count = 4 mean rate = 1.33 calls/second 1-minute rate = 0.00 calls/second 5-minute rate = 0.00 calls/second 15-minute rate = 0.00 calls/second min = 483.07 milliseconds max = 901.92 milliseconds mean = 612.64 milliseconds stddev = 196.32 milliseconds median = 532.79 milliseconds 75% <= 818.31 milliseconds 95% <= 901.92 milliseconds 98% <= 901.92 milliseconds 99% <= 901.92 milliseconds 99.9% <= 901.92 milliseconds 14-2-18 9:31:57 ================================================================ -- Timers ---------------------------------------------------------------------- com.netease.test.metrics.TestTimers.request count = 8 mean rate = 1.33 calls/second 1-minute rate = 1.40 calls/second 5-minute rate = 1.40 calls/second 15-minute rate = 1.40 calls/second min = 41.07 milliseconds max = 968.19 milliseconds mean = 639.50 milliseconds stddev = 306.12 milliseconds median = 692.77 milliseconds 75% <= 885.96 milliseconds 95% <= 968.19 milliseconds 98% <= 968.19 milliseconds 99% <= 968.19 milliseconds 99.9% <= 968.19 milliseconds 14-2-18 9:32:00 ================================================================ -- Timers ---------------------------------------------------------------------- com.netease.test.metrics.TestTimers.request count = 15 mean rate = 1.67 calls/second 1-minute rate = 1.40 calls/second 5-minute rate = 1.40 calls/second 15-minute rate = 1.40 calls/second min = 41.07 milliseconds max = 968.19 milliseconds mean = 591.35 milliseconds stddev = 302.96 milliseconds median = 650.56 milliseconds 75% <= 838.07 milliseconds 95% <= 968.19 milliseconds 98% <= 968.19 milliseconds 99% <= 968.19 milliseconds 99.9% <= 968.19 milliseconds */
Health Checks
Metrics提供了一个独立的模块:Health Checks,用于对Application、其子模块或者关联模块的运行是否正常做检测。该模块是独立metrics-core模块的,使用时则导入metrics-healthchecks包。
<dependency> <groupId>com.codahale.metrics</groupId> <artifactId>metrics-healthchecks</artifactId> <version>3.0.1</version> </dependency>
使用起来和与上述几种类型的Metrics有点类似,但是需要重新实例化一个Metrics容器HealthCheckRegistry,待检测模块继承抽象类HealthCheck并实现check()方法即可,然后将该模块注册到HealthCheckRegistry中,判断的时候通过isHealthy()接口即可。如下示例代码:
package com.netease.test.metrics; import com.codahale.metrics.health.HealthCheck; import com.codahale.metrics.health.HealthCheckRegistry; import java.util.Map; import java.util.Random; /** * User: hzwangxx * Date: 14-2-18 * Time: 9:57 */ public class DatabaseHealthCheck extends HealthCheck{ private final Database database; public DatabaseHealthCheck(Database database) { this.database = database; } @Override protected Result check() throws Exception { if (database.ping()) { return Result.healthy(); } return Result.unhealthy("Can't ping database."); } /** * 模拟Database对象 */ static class Database { /** * 模拟database的ping方法 * @return 随机返回boolean值 */ public boolean ping() { Random random = new Random(); return random.nextBoolean(); } } public static void main(String[] args) { // MetricRegistry metrics = new MetricRegistry(); // ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).build(); HealthCheckRegistry registry = new HealthCheckRegistry(); registry.register("database1", new DatabaseHealthCheck(new Database())); registry.register("database2", new DatabaseHealthCheck(new Database())); while (true) { for (Map.Entry<String, Result> entry : registry.runHealthChecks().entrySet()) { if (entry.getValue().isHealthy()) { System.out.println(entry.getKey() + ": OK"); } else { System.err.println(entry.getKey() + ": FAIL, error message: " + entry.getValue().getMessage()); final Throwable e = entry.getValue().getError(); if (e != null) { e.printStackTrace(); } } } try { Thread.sleep(1000); } catch (InterruptedException e) { } } } } /* console output: database1: OK database2: FAIL, error message: Can't ping database. database1: FAIL, error message: Can't ping database. database2: OK database1: OK database2: FAIL, error message: Can't ping database. database1: FAIL, error message: Can't ping database. database2: OK database1: FAIL, error message: Can't ping database. database2: FAIL, error message: Can't ping database. database1: FAIL, error message: Can't ping database. database2: FAIL, error message: Can't ping database. database1: OK database2: OK database1: OK database2: FAIL, error message: Can't ping database. database1: FAIL, error message: Can't ping database. database2: OK database1: OK database2: OK database1: FAIL, error message: Can't ping database. database2: OK database1: OK database2: OK database1: OK database2: OK database1: OK database2: FAIL, error message: Can't ping database. database1: FAIL, error message: Can't ping database. database2: FAIL, error message: Can't ping database. */
其他支持
metrics提供了对Ehcache、Apache HttpClient、JDBI、Jersey、Jetty、Log4J、Logback、JVM等的集成,可以方便地将Metrics输出到Ganglia、Graphite中,供用户图形化展示。
参考资料
https://github.com/dropwizard/metrics
http://blog.csdn.net/scutshuxue/article/details/8350135
http://blog.synyx.de/2013/09/yammer-metrics-made-easy-part-i/
http://blog.synyx.de/2013/09/yammer-metrics-made-easy-part-ii/