Micrometer为最流行的监控系统提供了一个简单的仪表客户端外观,允许仪表化JVM应用,而无需关心是哪个供应商提供的指标。它的作用和SLF4J类似,只不过它关注的不是Logging(日志),而是application metrics(应用指标)。简而言之,它就是应用监控界的SLF4J。

Micrometer(译:千分尺)

不妨看看SLF4J官网上对于SLF4J的说明:Simple Logging Facade for Java (SLF4J)

现在再看Micrometer的说明:Micrometer provides a simple facade over the instrumentation clients for the most popular monitoring systems.

Metrics(译:指标,度量)

Micrometer提供了与供应商无关的接口,包括 timers(计时器)gauges(量规)counters(计数器)distribution summaries(分布式摘要)long task timers(长任务定时器)。它具有维度数据模型,当与维度监视系统结合使用时,可以高效地访问特定的命名度量,并能够跨维度深入研究。

支持的监控系统:AppOptics , Azure Monitor , Netflix Atlas , CloudWatch , Datadog , Dynatrace , Elastic , Ganglia , Graphite , Humio , Influx/Telegraf , JMX , KairosDB , New Relic , Prometheus , SignalFx , Google Stackdriver , StatsD , Wavefront

1.  安装

Micrometer记录的应用程序指标用于观察、告警和对环境当前/最近的操作状态做出反应。

为了使用Micrometer,首先要添加你所选择的监视系统的依赖。以Prometheus为例:

1 <dependency>
2 <groupId>io.micrometer</groupId>
3 <artifactId>micrometer-registry-prometheus</artifactId>
4 <version>${micrometer.version}</version>
5 </dependency>

2.  概念

2.1.  Registry

Meter是收集关于你的应用的一系列指标的接口。Meter是由MeterRegistry创建的。每个支持的监控系统都必须实现MeterRegistry。

Micrometer中包含一个SimpleMeterRegistry,它在内存中维护每个meter的最新值,并且不将数据导出到任何地方。如果你还没有一个首选的监测系统,你可以先用SimpleMeterRegistry:

1 MeterRegistry registry = new SimpleMeterRegistry(); 

注意:如果你用Spring的话,SimpleMeterRegistry是自动注入的

Micrometer还提供一个CompositeMeterRegistry用于将多个registries结合在一起使用,允许同时向多个监视系统发布指标。

1 CompositeMeterRegistry composite = new CompositeMeterRegistry();
2
3 Counter compositeCounter = composite.counter("counter");
4 compositeCounter.increment();
5
6 SimpleMeterRegistry simple = new SimpleMeterRegistry();
7 composite.add(simple);
8
9 compositeCounter.increment();

2.2.  Meters

Micrometer提供一系列原生的Meter,包括Timer , Counter , Gauge , DistributionSummary , LongTaskTimer , FunctionCounter , FunctionTimer , TimeGauge。不同的meter类型导致有不同的时间序列指标值。例如,单个指标值用Gauge表示,计时事件的次数和总时间用Timer表示。

每一项指标都有一个唯一标识的名字和维度。“维度”和“标签”是一个意思,Micrometer中有一个Tag接口,仅仅因为它更简短。一般来说,应该尽可能地使用名称作为轴心。

(PS:指标的名字很好理解,维度怎么理解呢?如果把name想象成横坐标的话,那么dimension就是纵坐标。Tag是一个key/value对,代表指标的一个维度值)

2.3.  Naming meters(指标命名)

Micrometer使用了一种命名约定,用.分隔小写单词字符。不同的监控系统有不同的命名约定。每个Micrometer的实现都要负责将Micrometer这种以.分隔的小写字符命名转换成对应监控系统推荐的命名。你可以提供一个自己的NamingConvention来覆盖默认的命名转换:

1 registry.config().namingConvention(myCustomNamingConvention); 

有了命名约定以后,下面这个timer在不同的监控系统中看起来就是这样的:

1 registry.timer("http.server.requests"); 

在Prometheus中,它是http_server_requests_duration_seconds

在Atlas中,它对应的是httpServerRequests

在InfluxDB中,对应的是http_server_requests

(PS:每项指标都有一个名字,不同的监控系统的命名规则(风格)都不太一样,因此可能同一个指标在不同的监控系统中有不同的名字。简单地来说,比如内存使用率这个指标可能在Prometheus中用MemoryUsage表示,在InfluxDB中用mem_usage表示,因此每个监控系统都要提供一个命名转换器,当看到mem.usage的时候InfluxDB应该知道说的是内存使用率,对应的指标名称是mem_usage。这就好比,中文“你好”翻译成英文是“hello”,翻译成日文是“こんにちは” )

2.3.1.  Tag naming

假设,我们想要统计HTTP请求数和数据库调用次数,那么可以这样写:

1 registry.counter("database.calls", "db", "users");       // 数据库调用次数
2 registry.counter("http.requests", "uri", "/api/users"); // HTTP请求数

2.3.2.  Common tags

Common tags可以被定义在registry级别,并且会被添加到每个监控系统的报告中

预定义的Tags有host , instance , region , stack等

1 registry.config().commonTags("stack", "prod", "region", "us-east-1");
2 registry.config().commonTags(Arrays.asList(Tag.of("stack", "prod"), Tag.of("region", "us-east-1"))); // 二者等价

2.3.4.  Tag values

Tag values must be non-null

2.4.  Meter filters

每个registry都可以配置指标过滤器,它有3个方法:

Deny (or accept) meters from being registered

Transform meter IDs

Configure distribution statistics for some meter types.

实现MeterFilter就可以加到registry中

1 registry.config()
2 .meterFilter(MeterFilter.ignoreTags("too.much.information"))
3 .meterFilter(MeterFilter.denyNameStartsWith("jvm")); 

过滤器按顺序应用,所有的过滤器形成一个过滤器链(chain)

2.4.1.  Deny/accept meters

接受或拒绝指标

1 new MeterFilter() {
2 @Override
3 public MeterFilterReply accept(Meter.Id id) {
4 if(id.getName().contains("test")) {
5 return MeterFilterReply.DENY;
6 }
7 return MeterFilterReply.NEUTRAL;
8 }
9 }

MeterFilter还提供了许多方便的静态方法用于接受或拒绝指标

2.4.2.  Transforming metrics 

一个转换过滤器可能是这样的:

1 new MeterFilter() {
2 @Override
3 public Meter.Id map(Meter.Id id) {
4 if(id.getName().startsWith("test")) {
5 return id.withName("extra." + id.getName()).withTag("extra.tag", "value");
6 }
7 return id;
8 }
9 }

2.5.  Counters(计数器)

Counter接口允许以固定的数值递增,该数值必须为正数。

 1 MeterRegistry registry = new SimpleMeterRegistry();
2
3 // 写法一
4 Counter counter = registry.counter("counter");
5
6 // 写法二
7 Counter counter = Counter
8 .builder("counter")
9 .baseUnit("beans") // optional
10 .description("a description of what this counter does") // optional
11 .tags("region", "test") // optional
12 .register(registry);

2.5.1.  Function-tracking counters

跟踪单调递增函数的计数器

1 Cache cache = ...; // suppose we have a Guava cache with stats recording on
2 registry.more().counter("evictions", tags, cache, c -> c.stats().evictionCount()); // evictionCount()是一个单调递增函数,用于记录缓存被剔除的次数

2.6.  Gauges

gauge是获取当前值的句柄。典型的例子是,获取集合、map、或运行中的线程数等。

MeterRegistry接口包含了用于构建gauges的方法,用于观察数字值、函数、集合和map。

1 List<String> list = registry.gauge("listGauge", Collections.emptyList(), new ArrayList<>(), List::size); //监视非数值对象
2 List<String> list2 = registry.gaugeCollectionSize("listSize2", Tags.empty(), new ArrayList<>()); //监视集合大小
3 Map<String, Integer> map = registry.gaugeMapSize("mapGauge", Tags.empty(), new HashMap<>()); 

还可以手动加减Gauge

1 AtomicInteger n = registry.gauge("numberGauge", new AtomicInteger(0));
2 n.set(1);
3 n.set(2);

2.7.  Timers(计时器)

Timer用于测量短时间延迟和此类事件的频率。所有Timer实现至少将总时间和事件次数报告为单独的时间序列。

例如,可以考虑用一个图表来显示一个典型的web服务器的请求延迟情况。服务器可以快速响应许多请求,因此定时器每秒将更新很多次。

 1 // 方式一
2 public interface Timer extends Meter {
3 ...
4 void record(long amount, TimeUnit unit);
5 void record(Duration duration);
6 double totalTime(TimeUnit unit);
7 }
8
9 // 方式二
10 Timer timer = Timer
11 .builder("my.timer")
12 .description("a description of what this timer does") // optional
13 .tags("region", "test") // optional
14 .register(registry); 

查看源代码,一目了然,不一一赘述

2.8.  Long task timers

长任务计时器用于跟踪所有正在运行的长时间运行任务的总持续时间和此类任务的数量。

Timer记录的是次数,Long Task Timer记录的是任务时长和任务数

 1 // 方式一
2 @Timed(value = "aws.scrape", longTask = true)
3 @Scheduled(fixedDelay = 360000)
4 void scrapeResources() {
5 // find instances, volumes, auto-scaling groups, etc...
6 }
7
8 // 方式二
9 LongTaskTimer scrapeTimer = registry.more().longTaskTimer("scrape");
10 void scrapeResources() {
11 scrapeTimer.record(() => {
12 // find instances, volumes, auto-scaling groups, etc...
13 });
14 }

2.9.  Distribution summaries(分布汇总)

distribution summary用于跟踪分布式的事件。它在结构上类似于计时器,但是记录的值不代表时间单位。例如,记录http服务器上的请求的响应大小。

1 DistributionSummary summary = registry.summary("response.size");

2.10.  Histograms and percentiles(直方图和百分比)

Timers 和 distribution summaries 支持收集数据来观察它们的百分比。查看百分比有两种主要方法:

Percentile histograms(百分比直方图):  Micrometer将值累积到底层直方图,并将一组预先确定的buckets发送到监控系统。监控系统的查询语言负责从这个直方图中计算百分比。目前,只有Prometheus , Atlas , Wavefront支持基于直方图的百分位数近似值,并且通过histogram_quantile , :percentile , hs()依次表示。

Client-side percentiles(客户端百分比):Micrometer为每个meter ID(一组name和tag)计算百分位数近似值,并将百分位数值发送到监控系统。

下面是用直方图构建Timer的一个例子:

1 Timer.builder("my.timer")
2 .publishPercentiles(0.5, 0.95) // median and 95th percentile
3 .publishPercentileHistogram()
4 .sla(Duration.ofMillis(100))
5 .minimumExpectedValue(Duration.ofMillis(1))
6 .maximumExpectedValue(Duration.ofSeconds(10))

3.  Micrometer Prometheus

Prometheus是一个内存中的维度时间序列数据库,具有简单的内置UI、定制查询语言和数学操作。Prometheus的设计是基于pull模型进行操作,根据服务发现定期从应用程序实例中抓取指标。

3.1.  安装

1 <dependency>
2 <groupId>io.micrometer</groupId>
3 <artifactId>micrometer-registry-prometheus</artifactId>
4 <version>${micrometer.version}</version>
5 </dependency>

3.2.  配置

Prometheus希望通过抓取或轮询单个应用程序实例来获得指标。除了创建Prometheus registry之外,还需要向Prometheus的scraper公开一个HTTP端点。在Spring环境中,一个Prometheus actuator endpoint是在Spring Boot Actuator存在的情况下自动配置的。

下面的示例使用JDK的com.sun.net.httpserver.HttpServer来公布scrape端点:

 1 PrometheusMeterRegistry prometheusRegistry = new PrometheusMeterRegistry(PrometheusConfig.DEFAULT);
2
3 try {
4 HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
5 server.createContext("/prometheus", httpExchange -> {
6 String response = prometheusRegistry.scrape();
7 httpExchange.sendResponseHeaders(200, response.getBytes().length);
8 try (OutputStream os = httpExchange.getResponseBody()) {
9 os.write(response.getBytes());
10 }
11 });
12
13 new Thread(server::start).start();
14 } catch (IOException e) {
15 throw new RuntimeException(e);
16 }

3.3.  图表

Grafana Dashboard

4.  Spring Boot 2.0

Spring Boot Actuator提供依赖管理并自动配置Micrometer

Spring Boot 自动配置一个组合的MeterRegistry,并添加一个registry到这个组合MeterRegistry中。

你可以注册任意数量的MeterRegistryCustomizer来进一步配置registry

1 @Bean
2 MeterRegistryCustomizer<MeterRegistry> metricsCommonTags() {
3 return registry -> registry.config().commonTags("region", "us-east-1");
4 }

你可以在组件中注入MeterRegistry,并注册指标:

 1 @Component
2 public class SampleBean {
3
4 private final Counter counter;
5
6 public SampleBean(MeterRegistry registry) {
7 this.counter = registry.counter("received.messages");
8 }
9
10 public void handleMessage(String message) {
11 this.counter.increment();
12 // handle message implementation
13 }
14
15 }

Spring Boot为Prometheus提供/actuator/prometheus端点

下面是一个简单的例子,scrape_config添加到prometheus.yml中:

1 scrape_configs:
2 - job_name: 'spring'
3 metrics_path: '/actuator/prometheus'
4 static_configs:
5 - targets: ['HOST:PORT']

5.  JVM、Cache、OkHttpClient

Micrometer提供了几个用于监视JVM、Cache等的binder。例如:

 1 new ClassLoaderMetrics().bindTo(registry);
2 new JvmMemoryMetrics().bindTo(registry);
3 new JvmGcMetrics().bindTo(registry);
4 new ProcessorMetrics().bindTo(registry);
5 new JvmThreadMetrics().bindTo(registry);
6
7 // 通过添加OkHttpMetricsEventListener来收集OkHttpClient指标
8 OkHttpClient client = new OkHttpClient.Builder()
9 .eventListener(OkHttpMetricsEventListener.builder(registry, "okhttp.requests")
10 .tags(Tags.of("foo", "bar"))
11 .build())
12 .build();
13 // 为了配置URI mapper,可以用uriMapper()
14 OkHttpClient client = new OkHttpClient.Builder()
15 .eventListener(OkHttpMetricsEventListener.builder(registry, "okhttp.requests")
16 .uriMapper(req -> req.url().encodedPath())
17 .tags(Tags.of("foo", "bar"))
18 .build())
19 .build(); 

还有很多内置的Binder,看图:

最后,切记文档是用来查的,此处只是一个引子,有个大概印象,等需要用的时候再细查文档即可。

6.  文档

http://micrometer.io

http://micrometer.io/docs

Micrometer 快速入门的更多相关文章

  1. Web Api 入门实战 (快速入门+工具使用+不依赖IIS)

    平台之大势何人能挡? 带着你的Net飞奔吧!:http://www.cnblogs.com/dunitian/p/4822808.html 屁话我也就不多说了,什么简介的也省了,直接简单概括+demo ...

  2. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

  3. 前端开发小白必学技能—非关系数据库又像关系数据库的MongoDB快速入门命令(2)

    今天给大家道个歉,没有及时更新MongoDB快速入门的下篇,最近有点小忙,在此向博友们致歉.下面我将简单地说一下mongdb的一些基本命令以及我们日常开发过程中的一些问题.mongodb可以为我们提供 ...

  4. 【第三篇】ASP.NET MVC快速入门之安全策略(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  5. 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  6. Mybatis框架 的快速入门

    MyBatis 简介 什么是 MyBatis? MyBatis 是支持普通 SQL 查询,存储过程和高级映射的优秀持久层框架.MyBatis 消除 了几乎所有的 JDBC 代码和参数的手工设置以及结果 ...

  7. grunt快速入门

    快速入门 Grunt和 Grunt 插件是通过 npm 安装并管理的,npm是 Node.js 的包管理器. Grunt 0.4.x 必须配合Node.js >= 0.8.0版本使用.:奇数版本 ...

  8. 【第一篇】ASP.NET MVC快速入门之数据库操作(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

  9. 【第四篇】ASP.NET MVC快速入门之完整示例(MVC5+EF6)

    目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...

随机推荐

  1. Http请求传json数据中文乱码问题

    业务场景:调easyui的dialog打开一个弹窗,传参是用json封装的,而且有中文,然后在极速模式是正常的,在ie11测试发现中文出现乱码了 var params = JSON.stringify ...

  2. Java异常机制及异常处理建议

    1.Java异常机制 异常指不期而至的各种状况,如:文件找不到.网络连接失败.非法参数等.异常是一个事件,它发生在程序运行期间,干扰了正常的指令流程.Java通过API中Throwable类的众多子类 ...

  3. emlog博客的安装教程

    简介 emlog 是一款基于PHP和MySQL的功能强大的博客及CMS建站系统.致力于为您提供快速.稳定,且在使用上又极其简单.舒适的内容创作及站点搭建服务. 安装步骤 1.将src文件夹下的所有文件 ...

  4. 终于跑通分布式事务框架tcc-transaction的示例项目

    1.背景 前段时间在看项目代码的时候,发现有些接口的流程比较长,在各个服务里面都有通过数据库事务保证数据的一致性,但是在上游的controller层并没有对一致性做保证. 网上查了下,还没找到基于Go ...

  5. mongodb 启动 WARNING: soft rlimits too low, transparent_hugepage/enabled is 'always'. never

    今天启动mongodb的时候,之前一直没注意,今天发现又warning,想整一整. 下面是告警 2019-09-05T12:00:55.271+0800 I CONTROL [initandliste ...

  6. Badboy - 导出脚本,用于JMeter性能测试

    参考: http://leafwf.blog.51cto.com/872759/1131119 http://www.51testing.com/html/00/130600-1367743.html ...

  7. POJ-1222EXTENDED LIGHTS OUT-位运算枚举模板

    传送门:http://poj.org/problem?id=1222 题意:开关灯问题,一幅开关的灯中,给出一种操作,使得灯全关掉,(操作一个开关,相邻的灯也会改变) 思路:利用位运算枚举第一行: # ...

  8. CodeForces 1105E Helping Hiasat 最大独立集

    Helping Hiasat 题解: 如果我们把连续的2出现的人都相互连边的话, 题目就是问最大独立集的答案是多少. 求最大独立集可以将图变成反图, 然后求最大团. 代码: #include<b ...

  9. 树状数组求区间和模板 区间可修改 参考题目:牛客小白月赛 I 区间

    从前有个东西叫树状数组,它可以轻易实现一些简单的序列操作,比如单点修改,区间求和;区间修改,单点求值等. 但是我们经常需要更高级的操作,比如区间修改区间查询.这时候树状数组就不起作用了,只能选择写一个 ...

  10. webstorm 突然不能用了?解决办法~

    首先   感谢http://idea.lanyus.com 提供的试用方法,就在刚刚,webstorm突然就不能使了,http://idea.lanyus.com立马给出了解决办法,就是在hosts文 ...