Metrics即度量的意思,我们对系统做监控、统计等就需要用到Metrics。
metrics地址:https://github.com/dropwizard/metrics
文档地址:https://metrics.dropwizard.io/4.0.0/

本文使用的metrics-core和metrics-influxdb版本如下:
metrics-core=4.0.0
metrics-influxdb=0.8.0
jdk版本1.8

使用metrics统计controller的访问数

maven依赖

添加metrics-core

1
2
3
4
5
<dependency>
  <groupId>io.dropwizard.metrics</groupId>
  <artifactId>metrics-core</artifactId>
  <version>${metrics.version}</version>
</dependency>

定义Metric配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
public class MetricsConfig {

    @Bean
    public MetricRegistry metricRegistry() {
        MetricRegistry registry = new MetricRegistry();

        // 输出到控制台
        ConsoleReporter reporter = ConsoleReporter.forRegistry(registry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertRatesTo(TimeUnit.SECONDS)
                .build();
        reporter.start(5,TimeUnit.SECONDS);
        return registry;
    }

    @Bean
    public Meter userControllerMeter(MetricRegistry registry) {
        Meter meter = registry.meter("userControllerMeter");
        return meter;
    }
}

测试Controller:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
@Controller
@RequestMapping(value = "/user")
public class UserController {
    @Autowired
    @Qualifier("userControllerMeter")
    private Meter userControllerMeter;

    /**
     * 存储用户信息的List。
     */
    private Map<String,String> userInfos = new HashMap<String,String>(5) {{
        put("test","测试用户");
        put("root","root用户");
        put("admin","管理员");
    }};

    @RequestMapping(value = "/get")
    public ModelAndView test(ModelAndView mv, @RequestParam String userid) {
        userControllerMeter.mark();

        String user = getUserById(userid);

        mv.setViewName("/test");
        mv.addObject("user",user);
        return mv;
    }

    /**
     * 模拟一个获取用户信息的操作。
     * @param userid
     * @return
     */
    private String getUserById(String userid) {
        if (StringUtils.isEmpty(userid)) {
            return null;
        }

        // 这里模拟是一个耗时的操作,比如从其他系统获取用户信息。
        long sleepTime = (long) (Math.random()*10*1000+1);
        try {
            Thread.sleep(sleepTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return userInfos.get(userid);
    }
}

在浏览器中输入http://localhost:8081/user/get?userid=test,并访问多次。
控制台输出:

可以看到,Meters统计了总的访问次数,当前的频率(每秒多少次),1分钟内、5分钟内、15分钟内的频率。

使用Metrics统计某个方法的调用时间

这里我们统计调用UserController中
1.MetricsConfig增加:

1
2
3
4
5
@Bean
public Timer getUserTime(MetricRegistry registry) {
    Timer timer = registry.timer("getUserTimeTimer");
    return timer;
}

2.UserController修改

1
2
3
4
5
6
7
8
@Autowired
@Qualifier("getUserTime")
private Timer getUserTime;

// 统计调用getUserById耗费的时间
Timer.Context context = getUserTime.time();
String user = getUserById(userid);
context.stop();

在浏览器中输入http://localhost:8081/user/get?userid=test,并访问多次。
控制台输出:

可以看到,Timer统计了总的调用次数,当前的调用次数(每秒多少次)、1分钟、5分钟、15分钟,最小耗时,最大耗时,平均耗时,75%的调用耗时,95%,98%,99%的调用耗时。

Metrics数据的可视化

这里以Influxdb和Grafana来构建一个实时的监控界面。
处理流程如下:采集数据(Metrics)——>存储数据(InfluxDB)——>展示数据(Grafana)。

安装InfluxDB

1
2
wget http://dl.influxdata.com/influxdb/releases/influxdb-0.12.2-1.x86_64.rpm
yum localinstall influxdb-0.12.2-1.x86_64.rpm

安装后启动服务:

1
service influxdb start


启动成功后,浏览器输入ip:8083访问。

到设置中,

可以看到http端口为8086,用户名和密码为空,这里我们设置用户名和密码都为root。

安装Grafana

参考:https://blog.csdn.net/syshzbtt/article/details/71574204

1
2
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-4.2.0-1.x86_64.rpm 
sudo yum localinstall grafana-4.2.0-1.x86_64.rpm

安装后启动服务:

1
service grafana-server start


浏览器输入IP:3000访问,用户名和密码为admin。

将数据收集到Influxdb

前面我们将数据直接输出到控制台,我们制定的Metrics Reporter为ConsoleReporter,这里写入Influxdb,需要引入一个依赖:

1
2
3
4
5
<dependency>
  <groupId>com.github.davidb</groupId>
  <artifactId>metrics-influxdb</artifactId>
  <version>${metrics.influxdb.version}</version>
</dependency>

MetricsConfig修改:
我们将收集到的统计数据发送到InfluxDB

1
2
3
4
5
6
7
8
9
ScheduledReporter reporter = InfluxdbReporter.forRegistry(registry)
        // influxdb的ip,port,用户名,密码,数据库
        .protocol(InfluxdbProtocols.http("192.168.200.99",8086,"root","root","my-influxdb"))
        .convertRatesTo(TimeUnit.SECONDS)
        .convertDurationsTo(TimeUnit.MILLISECONDS)
        .filter(MetricFilter.ALL)
        .skipIdleMetrics(false)
        .build();
reporter.start(5,TimeUnit.SECONDS);

我们到InfluxDB的管理页面创建一个数据库

点击Create Database,在Query中填入CREATE DATABASE "my-influxdb"

然后回车,数据库就创建好了。

在Grafana的管理页面新建一个DataSource

Home页面,New一个dashboard

Graph

Panel Title

Edit

General可以修改标题
Metrics中,点SQL可以可视化编辑SQL。A From后面的default是默认数据源(在上面新建数据源时可以指定为默认数据源,或自己指定为你上面创建数据源名称),userControllerMeter是表名。在上面MetricsConfig中指定的名称,我们也可以在Influxdb中根据它来查询。如图:

第二行field(value)即我们要监控的指标,这里对应的就是count字段,ALIAY BY即是字段的别名,图表中显示用。点空白处,如果图表还是没数据,将日期显示范围扩大。
这样,就可以看到如下的图表

遇到的问题:

1
Caused by: java.lang.UnsupportedClassVersionError: com/justin/metrics/config/MetricsConfig : Unsupported major.minor version 52.0 (unable to load class com.justin.metrics.config.MetricsConfig)。

我的metrics-demo模块用的jdk7,引入的metrics-influxdb版本是0.8.2(mvn仓库最低就是这个版本),但0.8.2使用的jdk8编译的,所以有这个问题。
但是,将metrics-demo模块的jdk改成1.8后,还是有这个问题。最后更改整个project的版本为1.8解决。

这里只是作为一个演示,这是偏运维的东西,但作为开发人员还是有必要了解一下。

参考:https://www.jianshu.com/p/e4f70ddbc287https://www.jianshu.com/p/fadcf4d92b0e

源代码:https://gitee.com/qincd/my-test-projects/metrics-demo模块。