它是一个工具集,不是一个框架。它在kafka,spark,hadoop,flink和cassandra等流行框架中都得到了广泛的应用。
官网:https://metrics.dropwizard.io
meter用于统计基于时间的时间率(event rate over time),主要包含:
(1)监控开始至当前总共接收的时间数量
(2)估算的平均事件率
(3)估算的1min内的事件率
(4)估算的5min内的事件率
(5)估算的15min内的事件率
(1)pom依赖
io.dropwizard.metrics
metrics-core
3.2.6
(2)代码
public class MeterMetricsDemo {
//metrics注册中心
private static final MetricRegistry metrics = new MetricRegistry();
//创建meter类型的监控,并注册到注册中心,name会作为统计结果的标题,它用于统计请求事件率
/**
* -- Meters ----------------------------------------------------------------------
* reqRate
*/
private static final Meter reqRate = metrics.meter("reqRate");
//用于统计请求体的大小
/**
* -- Meters ----------------------------------------------------------------------
* reqSize
*/
private static final Meter reqSize = metrics.meter("reqSize");
public static void main(String[] args) {
startReport();
while (true) {
sleepRandomSeconds();
response(new byte[ThreadLocalRandom.current().nextInt(10_000_000)]);
}
}
private static void response(byte[] request){
System.out.println("==========接收到请求");
reqRate.mark();
reqSize.mark(request.length);
}
private static void startReport() {
ConsoleReporter reporter =
//给metrics设置报告模式
ConsoleReporter.forRegistry(metrics)
//设置事件率的统计事件,例如events/second,events/millisecond, events/hour...
.convertRatesTo(TimeUnit.SECONDS)
//Timer类型的metrics才会用到,meter不起作用
//.convertDurationsTo(TimeUnit.HOURS)
.build();
//设置每隔多长时间间隔打印一次报告,例如每隔3s打印一次报告
reporter.start(3, TimeUnit.SECONDS);
}
private static void sleepRandomSeconds() {
int random = ThreadLocalRandom.current().nextInt(3);
try {
TimeUnit.SECONDS.sleep(random);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
(3)日志输出
==========接收到请求
==========接收到请求
==========接收到请求
22-3-31 22:09:46 ===============================================================
-- Meters ---
-------------------------------------------------------------------
reqRate
count = 4
mean rate = 1.15 events/second
1-minute rate = 0.00 events/second
5-minute rate = 0.00 events/second
15-minute rate = 0.00 events/second
reqSize
count = 20404333
mean rate = 5858540.55 events/second
1-minute rate = 0.00 events/second
5-minute rate = 0.00 events/second
15-minute rate = 0.00 events/second
==========接收到请求
22-3-31 22:09:49 ===============================================================
-- Meters ----------------------------------------------------------------------
reqRate
count = 5
mean rate = 0.77 events/second
1-minute rate = 1.00 events/second
5-minute rate = 1.00 events/second
15-minute rate = 1.00 events/second
reqSize
count = 23931535
mean rate = 3686812.79 events/second
1-minute rate = 4786307.00 events/second
5-minute rate = 4786307.00 events/second
15-minute rate = 4786307.00 events/second
gauge用户记录某一时刻的value值,例如某时刻queue的size,某一时刻cache的逐出数...
示例代码:
public class QueueManager {
private final Queue queue;
public QueueManager(MetricRegistry metrics, String name) {
this.queue = new Queue();
//每个metric在registry中必需有一个唯一的名字,名字是一个点号分割的字符串
//例如:com.john.metrics.gauge.QueueManager.mktPriceQueue.size
metrics.register(MetricRegistry.name(QueueManager.class, name, "size"),
(Gauge) queue::size);
}
}
QueueManager queueManager = new QueueManager(metrics, "mktPriceQueue");
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
//Timer和Meter才起作用
//.convertRatesTo(TimeUnit.SECONDS)
.build();
日志输出:
22-4-1 9:13:31 =================================================================
-- Gauges ----------------------------------------------------------------------
com.john.metrics.gauge.QueueManager.mktPriceQueue.size
value = 3
22-4-1 9:13:34 =================================================================
-- Gauges ----------------------------------------------------------------------
com.john.metrics.gauge.QueueManager.mktPriceQueue.size
value = 14
可以使用jmx的数据
代码示例:
public class JmxGaugeDemo {
private static final MetricRegistry registry = new MetricRegistry();
private static final ConsoleReporter repoter = ConsoleReporter.forRegistry(registry)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.SECONDS)
.build();
public static void main(String[] args) throws MalformedObjectNameException {
repoter.start(3, TimeUnit.SECONDS);
registry.register(MetricRegistry.name(JmxGaugeDemo.class, "HeapMemory"), new JmxAttributeGauge(
new ObjectName("java.lang:type=Memory"), "HeapMemoryUsage"
));
registry.register(MetricRegistry.name(JmxGaugeDemo.class, "NonHeapMemory"), new JmxAttributeGauge(
new ObjectName("java.lang:type=Memory"), "NonHeapMemoryUsage"
));
while (true){}
}
}
日志示例:
22-4-2 18:18:02 ================================================================
-- Gauges ----------------------------------------------------------------------
com.john.metrics.gauge.JmxGaugeDemo.HeapMemory
value = javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=java.lang.management.MemoryUsage,items=((itemName=committed,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=init,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=max,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=used,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)))),contents={committed=126877696, init=132120576, max=1875378176, used=8088400})
com.john.metrics.gauge.JmxGaugeDemo.NonHeapMemory
value = javax.management.openmbean.CompositeDataSupport(compositeType=javax.management.openmbean.CompositeType(name=java.lang.management.MemoryUsage,items=((itemName=committed,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=init,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=max,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)),(itemName=used,itemType=javax.management.openmbean.SimpleType(name=java.lang.Long)))),contents={committed=10682368, init=2555904, max=-1, used=9314576})
代码示例:
public class RatioGaugeDemo {
private static final MetricRegistry registry = new MetricRegistry();
private static final ConsoleReporter repoter = ConsoleReporter.forRegistry(registry)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.SECONDS)
.build();
private static final Meter totalMeter = new Meter();
private static final Meter successMeter = new Meter();
public static void main(String[] args) {
repoter.start(3, TimeUnit.SECONDS);
registry.register("successRatio", new RatioGauge() {
@Override
protected Ratio getRatio() {
return Ratio.of(successMeter.getCount(), totalMeter.getCount());
}
});
while (true) {
doBusiness();
SleepRandomUtil.sleep(2);
}
}
private static void doBusiness(){
totalMeter.mark();
try{
int count = ThreadLocalRandom.current().nextInt(2);
if(count == 0){
System.out.println(">>>>>>>>>>>>>>");
}
int res = 3 / count;
successMeter.mark();
} catch (Exception e) {
}
}
}
日志示例:
22-4-2 18:52:34 ================================================================
-- Gauges ----------------------------------------------------------------------
successRatio
value = 0.8888888888888888
代码示例:
public class CachedGaugeDemo {
private static final MetricRegistry registry = new MetricRegistry();
private static final ConsoleReporter repoter = ConsoleReporter.forRegistry(registry)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.SECONDS)
.build();
public static void main(String[] args) {
repoter.start(3, TimeUnit.SECONDS);
//10s中时间内都是从缓存中获取
registry.register("cachedGauge", new CachedGauge(5, TimeUnit.SECONDS) {
@Override
protected Long loadValue() {
return queryFromDb();
}
});
while (true){}
}
private static Long queryFromDb(){
SleepRandomUtil.sleep(2);
return Long.valueOf(ThreadLocalRandom.current().nextInt(10_000));
}
}
日志示例:
22-4-2 19:11:03 ================================================================
-- Gauges ----------------------------------------------------------------------
cachedGauge
value = 6828
22-4-2 19:11:06 ================================================================
-- Gauges ----------------------------------------------------------------------
cachedGauge
value = 6828
22-4-2 19:11:09 ================================================================
-- Gauges ----------------------------------------------------------------------
cachedGauge
value = 3615
counter是一个使用AtomicLong进行存储的计数器,可以增减其值。自身值的增减可以减少对queue API操作而对其性能的影响。
代码示例:
public class SimpleCounter {
private static final MetricRegistry registry = new MetricRegistry();
private static final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();
private static final ArrayBlockingQueue queue = new ArrayBlockingQueue<>(100);
private static final Counter counter = registry.counter(
MetricRegistry.name(SimpleCounter.class, "pendingJobs", "size"));
public static void main(String[] args) {
reporter.start(3, TimeUnit.SECONDS);
new Thread(() -> {
while (true) {
addMsg("hello");
counter.inc();
SleepRandomUtil.sleep(2);
}
}, "producer").start();
new Thread(() -> {
while (true) {
if(consumerMsg() != null){
counter.dec();
}
SleepRandomUtil.sleep(10);
}
}, "consumer").start();
while (true) {
}
}
public static void addMsg(String msg) {
try {
queue.put(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static String consumerMsg() {
try {
String msg = queue.take();
return msg;
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
日志示例:
-- Counters --------------------------------------------------------------------
com.john.metrics.counter.SimpleCounter.pendingJobs.size
count = 10
22-4-1 9:52:51 =================================================================
-- Counters --------------------------------------------------------------------
com.john.metrics.counter.SimpleCounter.pendingJobs.size
count = 13
直方图,用于统计数据流的统计分布。例如,统计搜索词对搜索结果的影响,统计某方法的调用时长...
代码示例:
public class HistogramsDemo {
private static final MetricRegistry registry = new MetricRegistry();
private static final Histogram responseSizes = registry.histogram(MetricRegistry.name(HistogramsDemo.class, "response-sizes"));
private static final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry).build();
public static void main(String[] args) {
reporter.start(3, TimeUnit.SECONDS);
while (true) {
response(new byte[ThreadLocalRandom.current().nextInt(10)]);
SleepRandomUtil.sleep(2);
}
}
private static void response(byte[] request){
responseSizes.update(request.length);
}
}
日志示例:
22-4-1 19:13:05 ================================================================
-- Histograms ------------------------------------------------------------------
com.john.metrics.histogram.HistogramsDemo.response-sizes
count = 5 //调用update的次数
min = 3 //最小的请求体大小
max = 8 //最大的请求体大小
mean = 4.38 //平均值
stddev = 1.95 //标准方差
median = 3.00 //中位值
75% <= 5.00 //75%的请求体大小小于5
95% <= 8.00 //95%的请求体大小小于8
98% <= 8.00 //98%的请求体大小小于8
99% <= 8.00 //99%的请求体大小小于8
99.9% <= 8.00 //99.9%的请求体大小小于8
22-4-1 19:13:08 ================================================================
-- Histograms ------------------------------------------------------------------
com.john.metrics.histogram.HistogramsDemo.response-sizes
count = 14
min = 0
max = 9
mean = 4.87
stddev = 3.09
median = 5.00
75% <= 8.00
95% <= 9.00
98% <= 9.00
99% <= 9.00
99.9% <= 9.00
计时器测量特定代码段被调用的速率及其耗时时间分布。
代码示例:
public class TimerDemo {
private static final MetricRegistry registry = new MetricRegistry();
private static final Timer timer = registry.timer(MetricRegistry.name(TimerDemo.class, "request"), Timer :: new);
private static final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
//统计每秒时间内调用多少次,例如:calls/second, calls/minute
.convertRatesTo(TimeUnit.SECONDS)
//每次调用的耗时统计单位,例如seconds, minutes
.convertDurationsTo(TimeUnit.SECONDS)
.build();
public static void main(String[] args) {
reporter.start(2, TimeUnit.SECONDS);
while (true) {
response(new byte[ThreadLocalRandom.current().nextInt(10)]);
}
}
private static void response(byte[] request){
Timer.Context context = timer.time();
try {
TimeUnit.SECONDS.sleep(2);
} catch (Exception e) {
}finally {
long stop = context.stop(); //nano seconds
System.out.println("elapse " + stop);
}
}
}
日志示例:
22-4-2 10:35:43 ================================================================
-- Timers ------------------------------------------------------------------
com.john.metrics.timer.TimerDemo.request
count = 12 //到目前位置调用了12次
mean rate = 0.50 calls/second //平均每秒调用0.5次
1-minute rate = 0.41 calls/second //1min窗口内的统计结果:每秒调用0.5次
5-minute rate = 0.40 calls/second //5min窗口内的统计结果:每秒调用0.5次
15-minute rate = 0.40 calls/second //15min窗口内的统计结果:每秒调用0.5次
min = 2.00 seconds //最小调用耗时2s
max = 2.00 seconds //最大调用耗时2s
mean = 2.00 seconds //平均调用耗时2s
stddev = 0.00 seconds //标准差0
median = 2.00 seconds //中位数2s
75% <= 2.00 seconds //75%的调用耗时小于等于2s
95% <= 2.00 seconds //95%的调用耗时小于等于2s
98% <= 2.00 seconds //98%的调用耗时小于等于2s
99% <= 2.00 seconds //99%的调用耗时小于等于2s
99.9% <= 2.00 seconds //99.9%的调用耗时小于等于2s