引言
对于后台服务而言,我们除了需要保证其每个功能正常工作,我们还需要了解服务的运行情况,包括机器的物理性能(线程数,文件句柄数,内存占用大小,GC时间等)以及业务性能(关键流程的通过率、QPS以及响应时间等)。目前,常用的做法是通过定义、收集以及展示一系列的指标(metrics)来完成后台服务的监控。
监控其实可以分为四部分,首先我们需要定义监控数据的产生,然后我们需要定义监控数据收集的规则,再后则是数据监控数据的展现形式,最后则是根据监控数据进行报警。本文会从监控数据的产生写起,逐步为大家介绍,如何在Java服务中接入监控服务。本文主要基于目前较为流行的metrics框架,codahale的metrics,其maven依赖如下所示:
<dependencies>
<dependency>
<groupId>com.codahale.metrics</groupId>
<artifactId>metrics-core</artifactId>
<version>3.1.2</version>
</dependency>
</dependencies>
Metrics中的基础数据类型
说到监控数据如何产生,就必须先从其基础的数据类型说起。下面介绍三种最常用的数据类型,Counter, Gauge, 以及Histogram。一般的Java Metrics库都会有这三者的实现。
Counter(计数器)
跟字面意思一样,Counter就是一个只增不减的计数器,主要就是用于统计总量,它的常用用法如下所示:
统计Api访问中异常(400/500)的次数
统计Api的调用量
统计特定事件发生的次数。
那么,Counter的底层又是如何实现的呢?尤其是在高并发的访问情况下面,如何保证Counter的自增原子性以及发生竞争时保证性能?
在codahale的源码里面,设置了如下的机制来确保Counter自增的原子性以及高性能。
- 使用base与cells机制
在源码中,每个Counter都会由两部分组成,简化代码如下
public class Counter {
transient volatile int busy;
transient volatile long base;
transient volatile Cell[] cells;
public void inc(long n) {
long b;
if(cells == null || !casBase(b=base, b+n))