读过第一篇,Springboot 之 actuator, 即对metrics有了一定认识和理解, 本文将以metrics-spring的annotation的方式来讲解, 如何使用dropwizard metrics。
1、什么是Dropwizard metrics?
能够帮助我们从各个角度度量已存在的java应用的成熟框架,简便地以jar包的方式集成进您的系统,可以以http、ganglia、graphite、log4j等方式提供全栈式的监控视野。
2、为什么要用该框架?
在springboot的领域内使用actuator是最优的选择, 然而web应用五花八门,如一些应用直接使用Jetty启动的web应用、一些已存在的非springboot的应用、其他一些如已服务很久的基于netty的java应用, springboot actuator就不那么适用了。
或者说你的应用直接是基于Dropwizard搭建起来的,使用dropwizard metrics会显得理所应当。总得来讲:只要是Java application 就可以使用dropwizard metrics来解决自己应用的应用级监控问题。
3、它能从哪些角度帮忙度量我们的java应用?
1. 注册jvm监控
通过集成好的AdminServlet访问之后的效果:
{
"version": "3.0.0",
"gauges": {
"dropwizard.metrics.controller.HelloWorldController.helloTime": {
"value": 1//变量helloTime的值
},
"dropwizard.metrics.controller.HelloWorldController.queueSize": {
"value": 2103581016//假的随机队列大小
},
"jvm.fd.usage": {
"value": 0.00888671875//文件句柄使用情况, 运维监控系统可根据该使用率报警
},
"jvm.gc.PS-MarkSweep.count": {
"value": 2// garbage collection MarkSweep算法清扫内存次数
},
"jvm.gc.PS-MarkSweep.time": {
"value": 172// garbage collection MarkSweep算法标记清扫内存时间
},
"jvm.gc.PS-Scavenge.count": {
"value": 5// 新生代收集次数
},
"jvm.gc.PS-Scavenge.time": {
"value": 309// 新生代收集时间
},
"jvm.memory.heap.committed": {
"value": 482869248// 堆内存的可用空间, 在jvm运行过程中随时都会变化
},
"jvm.memory.heap.init": {
"value": 536870912// 堆内存的初始化空间, jvm初始化时吃掉的内存,随着运行会变化
},
"jvm.memory.heap.max": {
"value": 482869248// 堆内存的最大值=。=
},
"jvm.memory.heap.usage": {
"value": 0.2461350531065503// 内存使用率, 运维监控系统可根据该使用率报警
},
"jvm.memory.heap.used": {
"value": 118851048// 已使用内存
},
"jvm.memory.non-heap.committed": {
"value": 55656448// 非堆内存的可用空间
},
"jvm.memory.non-heap.init": {
"value": 2555904//非堆内存初始化空间
},
"jvm.memory.non-heap.max": {
"value": -1
},
"jvm.memory.non-heap.usage": {
"value": -49202216
},
"jvm.memory.non-heap.used": {
"value": 49202216
},
"jvm.memory.pools.Code-Cache.committed": {
"value": 14942208// 尚可cache代码的内存空间大小
},
"jvm.memory.pools.Code-Cache.init": {
"value": 2555904// cache代码的内存初始化值
},
"jvm.memory.pools.Code-Cache.max": {
"value": 251658240// ...
},
"jvm.memory.pools.Code-Cache.usage": {
"value": 0.051141357421875// 使用率, 运维可根据该使用率报警
},
"jvm.memory.pools.Code-Cache.used": {
"value": 12870144
},
"jvm.memory.pools.Compressed-Class-Space.committed": {
"value": 4366336//压缩后可用的class空间
},
"jvm.memory.pools.Compressed-Class-Space.init": {
"value": 0
},
"jvm.memory.pools.Compressed-Class-Space.max": {
"value": 1073741824
},
"jvm.memory.pools.Compressed-Class-Space.usage": {
"value": 0.0034717321395874023
},
"jvm.memory.pools.Compressed-Class-Space.used": {
"value": 3727744
},
"jvm.memory.pools.Metaspace.committed": {
"value": 36347904// Metaspace为java8中代替PermGen的存在
},
"jvm.memory.pools.Metaspace.init": {
"value": 0
},
"jvm.memory.pools.Metaspace.max": {
"value": -1
},
"jvm.memory.pools.Metaspace.usage": {
"value": 0.8970071011522425
},
"jvm.memory.pools.Metaspace.used": {
"value": 32604328
},
"jvm.memory.pools.PS-Eden-Space.committed": {
"value": 197132288
},
"jvm.memory.pools.PS-Eden-Space.init": {
"value": 201326592
},
"jvm.memory.pools.PS-Eden-Space.max": {
"value": 203423744
},
"jvm.memory.pools.PS-Eden-Space.usage": {
"value": 0.4824112174437218
},
"jvm.memory.pools.PS-Eden-Space.used": {
"value": 98133896
},
"jvm.memory.pools.PS-Old-Gen.committed": {
"value": 268435456
},
"jvm.memory.pools.PS-Old-Gen.init": {
"value": 268435456
},
"jvm.memory.pools.PS-Old-Gen.max": {
"value": 268435456
},
"jvm.memory.pools.PS-Old-Gen.usage": {
"value": 0.07717740535736084
},
"jvm.memory.pools.PS-Old-Gen.used": {
"value": 20717152
},
"jvm.memory.pools.PS-Survivor-Space.committed": {
"value": 17301504
},
"jvm.memory.pools.PS-Survivor-Space.init": {
"value": 33554432
},
"jvm.memory.pools.PS-Survivor-Space.max": {
"value": 17301504
},
"jvm.memory.pools.PS-Survivor-Space.usage": {
"value": 0
},
"jvm.memory.pools.PS-Survivor-Space.used": {
"value": 0
},
"jvm.memory.total.committed": {
"value": 538525696
},
"jvm.memory.total.init": {
"value": 539426816
},
"jvm.memory.total.max": {
"value": 482869247
},
"jvm.memory.total.used": {
"value": 168056176
},
"jvm.thread-states.blocked.count": {
"value": 0
},
"jvm.thread-states.count": {
"value": 22
},
"jvm.thread-states.daemon.count": {
"value": 21
},
"jvm.thread-states.deadlock.count": {
"value": 0
},
"jvm.thread-states.deadlocks": {
"value": [ ]// 有该种类型线程问题也应该报警
},
"jvm.thread-states.new.count": {
"value": 0
},
"jvm.thread-states.runnable.count": {
"value": 5
},
"jvm.thread-states.terminated.count": {
"value": 0
},
"jvm.thread-states.timed_waiting.count": {
"value": 9//过多时可报警, 如 大于50000
},
"jvm.thread-states.waiting.count": {
"value": 8
}
}}
2. 使用Gauge.
代码:
效果:
{
"version": "3.0.0",
"gauges": {
"dropwizard.metrics.controller.HelloWorldController.helloTime": {
"value": 1//监控 helloTime的瞬时值
}
}}
3. 使用Timer.
代码:
访问效果:
{
"version": "3.0.0",
"timers": {
"dropwizard.metrics.controller.HelloWorldController.getPerson": {
"count": 0,// 访问该方法的总次数
"max": 0,// 最长时间
"mean": 0,// 平均时间
"min": 0,// 最短时间
"p50": 0,// 中位数
"p75": 0,// 75th 分位数
"p95": 0,// 95th 分位数
"p98": 0,// 98th 分位数
"p99": 0,// 99th 分位数
"p999": 0,// 999th 分位数
"stddev": 0,
"m15_rate": 0,// 15分钟 请求数/每秒的比率
"m1_rate": 0,// 1分钟 请求数/每秒的比率
"m5_rate": 0,// 5分钟 请求数/每秒的比率
"mean_rate": 0,// 平均每秒请求数
"duration_units": "seconds",//该Timer的单位
"rate_units": "calls/second"//比率单位
}
}}
4.使用CachedGauge, 不想要每次拿统计数据都真的去拿一次mq的queue size的时候使用
代码:
访问效果:
{
"version": "3.0.0",
"gauges": {
"dropwizard.metrics.controller.HelloWorldController.queueSize": {
"value": 422130431 // 统计的queue的size.
}
}}
5. 使用ExceptionMetered
代码:
{
"version": "3.0.0",
"meters": {
"dropwizard.metrics.controller.HelloWorldController.exception.exceptions": {
"count": 0, // 该方法报了多少次异常
"m15_rate": 0,
"m1_rate": 0,
"m5_rate": 0,
"mean_rate": 0,
"units": "events/second"
}
}}
6. 使用Counted
代码:
访问效果:
{
"version": "3.0.0",
"counters": {
"dropwizard.metrics.controller.HelloWorldController.count": {
"count": 0//访问了该方法多少次
}
}}
7. 使用Metric + Histograms
代码:
{
"version": "3.0.0",
"histograms": {
"dropwizard.metrics.controller.HelloWorldController.histogram": {
"count": 0,// 访问次数, 该效果与Time类似,请参阅Time的comments.
"max": 0,
"mean": 0,
"min": 0,
"p50": 0,
"p75": 0,
"p95": 0,
"p98": 0,
"p99": 0,
"p999": 0,
"stddev": 0
}
}}
5、自定义healthCheck.
自定义healthCheck需要继承类 HealthCheck 代码如图:
运行起来之后的效果:
至此,Java的两个(springboot actuator, dropwizard metrics) 比较强大好用的应用级监控都介绍完了,落地让运维监控的同学一起提升应用质量的availability吧!
附录:
本文源码: https://github.com/Agileaq/Dropwizard-metrics-example
Dropwizard metrics 首页: http://metrics.dropwizard.io/3.1.0/getting-started/
Metrics for spring which integrate dropwizard metrics jars with spring :https://github.com/ryantenney/metrics-spring
jvm,init,used,commited,max的含义,
http://blog.csdn.net/fanwu72/article/details/8936746
本文作者:钱晟龙 Arc_Qian(点融黑帮),现任点融网架构组产品研发工程师,主要任务是思考并尝试解决各类点融网迈出第一公里之后遇到的现实问题。