Histogram用来统计数据的分布。Histogram可以提供收集到的数据的最大值、最小值、平均值和中值,此外还能提供百分比分布,如75%,95%,99.9%等等。
Histogram是我学习Metrics的驱动之一。最初是想使用Histogram来优化接口处理统计能力。
看下下面的类图:
类图表示了Histogram需要用到的几类和个接口之间的关系,简单说明下:
- Sampling接口:意思是取样器,只有一个方法,作用是取出某一阶段的统计结果快照(Snapshot);
- Reservoir接口:数据池,所有的记录最终都会写入Reservoir实例并完成运算;Metrics提供了多种数据池来执行不同的抽样运算;
- Snapshot接口:快照接口,作用是对Reservoir中的数据进行二次计算并生成统计结果;Snapshot提供了统计数据的最大值、最小值、标准差、平均值、中值、95分位值等指标;
- Histogram类:实现了Sampling接口,是对外交互的入口。
老规矩,看一段示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class HistogramShow { public static void main(String[] args) throws InterruptedException { final MetricRegistry metrics = new MetricRegistry(); final ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics).build(); reporter.start(3, TimeUnit.SECONDS); Histogram histogram = new Histogram(new ExponentiallyDecayingReservoir()); metrics.register("方法执行时长统计", histogram); for (int i = 0; i < 100; i++) { long start = System.currentTimeMillis(); try { delayedMethod(); } finally { histogram.update(System.currentTimeMillis() - start); } } } private static void delayedMethod() throws InterruptedException { long time = (long) (Math.random() * 1000); System.out.println("------>>method used time: " + time); TimeUnit.MILLISECONDS.sleep(time); } } |
这段代码中定义了一个delayedMethod()
方法,该方法会随机sleep一段时间来模拟方法执行时长。代码主体就是使用Histogram报表来统计每三秒钟内这个方法的执行状态。
MetricRegistry也提供了Histogram实例的创建注册方法,不过为这里了更直观一些,还是使用了直接new关键字来构建Histogram实例。可以看到,每次创建Histogram对象都需要传入一个Reservoir接口的实例。
看下执行结果片段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
------>>method used time: 522 ------>>method used time: 537 ------>>method used time: 820 ------>>method used time: 669 19-8-24 16:59:41 =============================================================== -- Histograms ------------------------------------------------------------------ 方法执行时长统计 count = 3 min = 534 max = 820 mean = 632.10 stddev = 134.38 median = 538.00 75% <= 820.00 95% <= 820.00 98% <= 820.00 99% <= 820.00 99.9% <= 820.00 |
统计结果即是由Snapshot提供。
简单介绍下metrics提供的几种Reservoir:
UniformReservoir
:默认保存1028条记录,每次进行update操作的时候,首先会依次地将值填入1028条记录中,当记录满了之后,就会使用随机替换0 – 1027中的一条(随机抽样1028条记录)。因为是随机替换,所以也不需要进行加锁和解锁。SlidingWindowReservoir
:固定大小的数据池,从0到n-1填入数据,但是不会对数据进行更新,也不会进行加锁和解锁(固定抽样n条记录)。SlidingTimeWindowReservoir
:非固定大小的数据池,但是只会存储过去N秒的数据(抽样N秒内的记录)。使用ConcurrentSkipListMap进行存储。ExponentiallyDecayingReservoir
:固定大小的数据池。首先会逐个数据填满数据池,随后会将老的数据替换为新的数据(抽样n条最新的记录),使用ConcurrentSkipListMap进行存储。可以说是SlidingWindowReservoir
与SlidingTimeWindowReservoir
的结合。
就这样。
发表评论