这篇是之前监控工具——Metrics 快速入门的补充
代码地址
因为每个例子涉及代码较多,且包含测试用例,如果都贴到文章中内容过多,所以只贴出了部分代码。全部的代码在这里: https://gitee.com/daifyutils/springboot-samples。
Histogram此篇文章所属模块为:base-metrics
在使用Histogram进行指标统计的时候,可以看到其支持一个Reservoir类型的参数
public Histogram(Reservoir reservoir) {
this.reservoir = reservoir;
this.count = LongAdderProxy.create();
}
通过查看可以看到此参数支持的实现类有5种
ExponentiallyDecayingReservoir基于指数级别的抽样算法,根据更新时间与开始时间的差值转化为权重值,权重越大数据被保留的几率越大。 内部使用ConcurrentSkipListMap并发跳表来存储数据。它的大小没有限制,因此使用它对高频过程进行采样可能需要大量内存。因为它记录了每次测量。
使用方式
Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir());
使用这种方法可能会有内存问题,官方文档专门提醒过这个问题
UniformReservoirWhile SlidingTimeWindowReservoir is easier to understand than ExponentiallyDecayingReservoir, it is not bounded in size, so using it to sample a high-frequency process can require a significant amount of memory. Because it records every measurement, it’s also the slowest reservoir type.
随机抽样,随着更新次数的增加,数据被抽样的几率减少。
使用方式
Histogram histogram = new Histogram(new UniformReservoir());
或者
Histogram histogram = new Histogram(new UniformReservoir(1028));
SlidingWindowReservoir
只存最近N条数据的一种采样的指标分析模式
使用方式
public static void main(String[] args) throws InterruptedException {
initMetric();
// SlidingWindowReservoir(只存最近N条数据)
// 注册一个Histogram
Histogram histogram = new Histogram(new SlidingWindowReservoir(10));
registry.register(MetricRegistry.name(HistogramsTest.class, "request", "histogram"), histogram);
int i = 0;
while(true){
Thread.sleep(1000);
i++;
System.out.println(((i/10) + 1) * 100000);
histogram.update(((i/10) + 1) * 100000);
}
}
最开始输出内容
-- Histograms ------------------------------------------------------------------
dai.samples.metrics.HistogramsTest.request.histogram
count = 9
min = 100000
max = 100000
mean = 100000.00
stddev = 0.00
median = 100000.00
75% <= 100000.00
95% <= 100000.00
98% <= 100000.00
99% <= 100000.00
99.9% <= 100000.00
最后输出内容
dai.samples.metrics.HistogramsTest.request.histogram
count = 19
min = 200000
max = 200000
mean = 200000.00
stddev = 0.00
median = 200000.00
75% <= 200000.00
95% <= 200000.00
98% <= 200000.00
99% <= 200000.00
99.9% <= 200000.00
SlidingTimeWindowReservoir
只记录最近的指定时间范围的指标分析模式
使用方式
public static void main(String[] args) throws InterruptedException {
initMetric();
// SlidingTimeWindowReservoir(指定时间窗口重置数据)
// 注册一个Histogram
Histogram histogram = new Histogram(new SlidingTimeWindowReservoir(10,TimeUnit.SECONDS));
registry.register(MetricRegistry.name(HistogramsTest.class, "request", "histogram"), histogram);
int i = 0;
while(true){
Thread.sleep(1000);
i++;
System.out.println(((i/10) + 1) * 100000);
histogram.update(((i/10) + 1) * 100000);
}
}
最开始输出内容
-- Histograms ------------------------------------------------------------------
dai.samples.metrics.HistogramsTest.request.histogram
count = 9
min = 100000
max = 100000
mean = 100000.00
stddev = 0.00
median = 100000.00
75% <= 100000.00
95% <= 100000.00
98% <= 100000.00
99% <= 100000.00
99.9% <= 100000.00
最后输出内容
dai.samples.metrics.HistogramsTest.request.histogram
count = 19
min = 200000
max = 200000
mean = 200000.00
stddev = 0.00
median = 200000.00
75% <= 200000.00
95% <= 200000.00
98% <= 200000.00
99% <= 200000.00
99.9% <= 200000.00
SlidingTimeWindowArrayReservoir
SlidingTimeWindowArrayReservoir是对SlidingTimeWindowReservoir的优化。根据官方描述SlidingTimeWindowArrayReservoir提供了更低的内存开销。其GC开销比SlidingTimeWindow低60-80倍
使用方式
Histogram histogram = new Histogram(new SlidingTimeWindowArrayReservoir(1,TimeUnit.MINUTES));
对于其使用所需内存官方提供了相关的例子
TimerExample: 10K measurements / sec with reservoir storing time of 1 minute will take 10000 * 60 * 128 / 8 = 9600000 bytes ~ 9 megabytes
Timer提供了直方图的相关数据分析,其内部也初始化了一个Histogram
Timer timer = registry.timer(MetricRegistry.name(TimersTest.class,"get-latency"));
默认情况下其初始化的Timer使用ExponentiallyDecayingReservoir
MetricBuilderTIMERS = new MetricBuilder () { @Override public Timer newMetric() { return new Timer(); } @Override public boolean isInstance(Metric metric) { return Timer.class.isInstance(metric); } }; public Timer() { this(new ExponentiallyDecayingReservoir()); }
明白上面不同的参数类型我们可以在使用Timer的时候使用需要的Reservoir
public class ReservoirTimersTest extends MetricBase {
public static Random random = new Random();
public static void main(String[] args) throws InterruptedException {
initMetric();
MetricRegistry.MetricSupplier metricSupplier = () -> new Timer(new SlidingTimeWindowReservoir(1,TimeUnit.MINUTES));
Timer timer = registry.timer(MetricRegistry.name(TimersTest.class,"get-latency"),metricSupplier);
Timer.Context ctx;
while(true){
ctx = timer.time();
Thread.sleep(random.nextInt(1000));
ctx.stop();
}
}
}



