接上《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/