Metrics是一个Java工具包,里面有各种监控的工具,可以用来监控生产环境中代码的运行状态。通过集成Jetty、Logback、Log4j、Apache HttpClient、Ehcach、JDBI和Jersey等通用库,以及报表平台Ganglia和Graphite
提供的监控工具:
Gauges:用于某一个值的测量。
Counters:计数器是一个AtomicLong的实例,可以增加或减少其值。
Histograms: 统计数值的分布,例如最大值、最小值和平均值等。
Meters:测量一段时间内的事件发生率,例如TPS。
Timers:测量一段代码被调用的速率和持续时间的分布。
Health Checks:检测服务健康的状况。
提供的多种渠道输出:
ConsoleReporter:控制台
CsvReporter:CSV文件
Slf4jReporter:Logback、Log4j等日志输出
JmxReporter:基于JMX的输出
GangliaReporter:监控工具Ganglia
GraphiteReporter:监控工具Graphite
实际应用场景:
Meters:统计鉴权接口的吞吐量。
Gauges:定时输出缓存键的数量。
Counters:统计鉴权接口失败的次数。
Histograms: 统计鉴权接口的最大、最小、平均的响应时间。
Timers:统计鉴权接口响应时间的分布,同时输出吞吐量信息。
Health Checks:account模块是否存活。
基本使用Demo
1.引入相关依赖
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>3.0.1</version>
</dependency>
2.Counter计数器的使用 计数器 可以通过inc()和dec()方法对计数器做修改
package com.hqq.metrics;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Counter;
import com.codahale.metrics.CsvReporter;
import com.codahale.metrics.MetricRegistry;
import java.io.File;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class TestCounter {
/**
* 类似一个metrics容器,维护一个Map,可以是一个服务一个实例
*/
private static final MetricRegistry metricRegistry = new MetricRegistry();
/***
* 创建一个计数器
*
* 另一种方法:
* Counter counter = new Counter();
* metricRegistry.register(MetricRegistry.name(TestCounter.class,"counter-job"),counter);
*/
private static final Counter counter = metricRegistry.counter(MetricRegistry.name(TestCounter.class, "counter-job"));
/**
* 任务队列
*/
private static final Queue<String> queue = new LinkedBlockingQueue<>();
/**
* 控制台输出
*/
private static final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metricRegistry).build();
/**
* CSV文件输出
*/
private static final CsvReporter CSV_REPORTER = CsvReporter.forRegistry(metricRegistry).build(new File("/Users/xxxx/Works"));
/**
* 入口方法
*
* @param args
* @throws InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
consoleReporter.start(1000, TimeUnit.MILLISECONDS);
CSV_REPORTER.start(1000, TimeUnit.MILLISECONDS);
for (int i = 0; i < 10; i++) {
addToQueue("work");
Thread.sleep(1000);
}
}
/**
* 入队操作
*
* @param content
*/
private static void addToQueue(String content) {
counter.inc();
queue.offer(content);
}
/**
* 出队操作
*/
private static String takeFromQueue() {
counter.dec();
return queue.poll();
}
}
3.Guages使用 一般用来统计瞬时状态的数据信息
package com.hqq.metrics;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Gauge;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.MetricRegistry;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class TestGuages {
/**
* 类似一个metrics容器,维护一个Map,可以是一个服务一个实例
*/
private static final MetricRegistry metricRegistry = new MetricRegistry();
/**
* 任务队列
*/
private static final Queue<String> queue = new LinkedBlockingQueue<>();
/**
* 控制台输出
*/
private static final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metricRegistry).build();
public static void main(String[] args) throws InterruptedException {
// consoleReporter.start(3, TimeUnit.SECONDS);
consoleReporter.start(1000, TimeUnit.MILLISECONDS);
//创建大小统计Gauge
Gauge<Integer> sizeGauge = () -> queue.size();
//放入容器
metricRegistry.register(MetricRegistry.name(TestGuages.class, "guage-job", "size"), sizeGauge);
//测试JMX
JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).build();
jmxReporter.start();
//模拟操作
for (int i = 0; i < 10; i++) {
queue.add("work");
Thread.sleep(1000);
}
}
}
4.Meters使用 度量某个时间段的平均处理次数(request per second) 每1、5、15分钟的TPS
package com.hqq.metrics;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Meter;
import com.codahale.metrics.MetricRegistry;
public class TestMeters {
/**
* 类似一个metrics容器,维护一个Map,可以是一个服务一个实例
*/
private static final MetricRegistry metricRegistry = new MetricRegistry();
/**
* 任务队列
*/
private static final Meter requestMeter = metricRegistry.meter(MetricRegistry.name(TestMeters.class, "meters-job"));
/**
* 控制台输出
*/
private static final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metricRegistry).build();
public static void main(String[] args) throws InterruptedException {
// consoleReporter.start(1000, TimeUnit.MILLISECONDS);
//模拟操作
for (int i = 0; i < 20; i++) {
request();
}
double meanRate = requestMeter.getMeanRate();
System.out.println(meanRate);
}
/**
* 模拟请求
*/
private static void request() throws InterruptedException {
requestMeter.mark();
Thread.sleep(500);
}
}
5.Histograms使用 主要使用来统计数据的分布情况 最大值、最小值、平均值、中位数,百分比(75%、90%、95%、98%、99%和99.9%)
package com.hqq.metrics;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.Histogram;
import com.codahale.metrics.MetricRegistry;
import java.util.concurrent.TimeUnit;
public class TestHistograms {
/**
* 类似一个metrics容器,维护一个Map,可以是一个服务一个实例
*/
private static final MetricRegistry metricRegistry = new MetricRegistry();
/**
* 初始化Histogram
*/
private static final Histogram histogram = metricRegistry.histogram(MetricRegistry.name(TestHistograms.class, "histograms-job"));
/**
* 控制台输出
*/
private static final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metricRegistry).build();
public static void main(String[] args) throws InterruptedException {
consoleReporter.start(1000, TimeUnit.MILLISECONDS);
for (int i = 0; i < 10; i++) {
handleRequest(1000);
Thread.sleep(1000);
}
System.out.println(histogram.getSnapshot().getMean());
}
private static void handleRequest(Integer value) {
histogram.update(value);
}
}
6.Timer使用 主要是用来统计某一块代码段的执行时间以及其分布情况
package com.hqq.metrics;
import com.codahale.metrics.ConsoleReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Timer;
import java.util.concurrent.TimeUnit;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class TestTimers {
/**
* 类似一个metrics容器,维护一个Map,可以是一个服务一个实例
*/
private static final MetricRegistry metricRegistry = new MetricRegistry();
/**
* 初始化Timer
*/
private static final Timer timer = metricRegistry.timer(MetricRegistry.name(TestTimers.class, "timer-job"));
/**
* 控制台输出
*/
private static final ConsoleReporter consoleReporter = ConsoleReporter.forRegistry(metricRegistry).build();
public static void main(String[] args) {
consoleReporter.start(100, TimeUnit.MILLISECONDS);
for (int i = 0; i < 10; i++) {
handleRequest(330L);
}
// long millSeconds = NANOSECONDS.convert(new Double(timer.getSnapshot().getMean()).longValue(), TimeUnit.MILLISECONDS);
long convert = MILLISECONDS.convert(new Double(timer.getSnapshot().getMean()).longValue(), TimeUnit.NANOSECONDS);
System.out.println(convert);
// System.out.println(timer.getSnapshot().getMean() / 1000000);
}
private static void handleRequest(Long sleepMills) {
Timer.Context context = timer.time();
try {
Thread.sleep(sleepMills);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
context.stop();
}
}
}