深入理解 Metrics(五):Timers
1.Timers 的使用
account 模块在测量鉴权接口的过程中,使用 Histograms 测量响应时间的分布;使用 Meters 测量每秒处理的请求数。
如果想同时测量又不想写重复代码,有好的方式吗?其实 Metrics 已经为你准备好了工具:Timers。 借助于 Timers 工具,account 模块对 Redis 的性能进行了测试,下面是测试代码:
代码说明:
1. 主动创建 Timer,之后注册到 MetricRegistry 中。
2. 在 Redis 中预先设置好键值对。
3. 模拟 100 的并发,测试总次数 = 并发数 * 1000。
4. 在每个线程中单独持有 Jedis 实例。
5. 在测试的过程中统计校验失败数。
最后输出:
从上面的输出结果可以看出,Timers 不仅统计了请求时间分布,还统计了 1 分钟、5 分钟、15 分钟内每秒钟请求的次数。
2. Timers 的层次结构
Timer 类实现接口的方式使用的是适配器模式。Timer 通过持有 Histogram 的实例实现了 Sampling 统计响应时间分布的接口;通过持有 Meter 的实例实现了 Metered 事件发生频率的接口。 让我们看看核心代码:
3. 时钟
在 Timer 中其实还引用了 Clock 类,Clock 类主要用来追踪消耗的时间。
Clock 类定义两个方法:获取当前时间的 getTime()和用于时间标记的 getTick(),实现 getTime()使用的是 System.currentTimeMillis();实现 getTick()使用的是 System.nanoTime(),也许你不禁要问:使用 currentTimeMillis 和 nanoTime 的时机是什么?带着这个疑问我们来参考 JDK 帮助文档的定义:
currentTimeMillis:当前时间与协调世界时 1970 年 1 月 1 日午夜之间的时间差,常常结合 SimpleDateFormat 输出自定义格式的时间。 nanoTime:返回最准确的可用系统计时器的当前值,以纳秒为单位,此方法只能用于测量消耗的时间,与系统或钟表时间的其他任何时间概念无关。
在 nanoTime 方法声明的注释中,介绍了 nanoTime 的使用方式:
Metrics 测量消耗的时间使用的就是结束纳秒与开始纳秒的差值。
4. System.nanoTime() 实现
我对 nanoTime 的实现非常的好奇,想研究下底层究竟是怎样实现的,于是就有了下面的历程。
4.1 下载 jvm 源码
下载了 jvm hotspot OpenJDK 的源码,关于 nanoTime 的实现,jvm 提供了针对不同操作系统的实现,例如:linux、solaris 和 windows。
4.2 native 方法映射地址
4.3 定位实际调用的方法
通过设置布尔变量 isNano=true 定位到 os::javaTimeNanos 方法。
4.4 javaTimeNanos 方法初探
javaTimeNanos 通过调用 supports_monotonic_clock 来判定系统是否支持单调时钟。
那么什么是单调时钟呢?
在 Linux 操作系统中用户通过 date 命令设置系统时间,会导致系统时钟出现跳变,对协调运行时间的程序之间来说会有计时不准的问题,为此 Linux 提出了单调时钟的概念。
4.5 单调时钟的初始化
4.6 clock_gettime 函数说明
这个接口基于较新的 POSIX 标准,过低的 Linux 版本很可能会不支持。
4.7 实验
为了加深印象,在我本机写了测试代码。
看得出,我的本还是支持单调时钟的。
5. 结束语
如果 Linux 系统不支持单调时钟,就需要研究 gettimeofday 方法了。
深入理解 Metrics 系列文章:
版权声明: 本文为 InfoQ 作者【冰心的小屋】的原创文章。
原文链接:【http://xie.infoq.cn/article/4cde5ba6b1addb72c004dda11】。文章转载请联系作者。
评论