热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

微服务监控之二:Metrics+influxdb+grafana构建监控平台

系统开发到一定的阶段,线上的机器越来越多,就需要一些监控了,除了服务器的监控,业务方面也需要一些监控服务。Metrics作为一款监控指标的度量类库,提供了许多工具帮助开发者来完成自定义的监控工作

系统开发到一定的阶段,线上的机器越来越多,就需要一些监控了,除了服务器的监控,业务方面也需要一些监控服务。Metrics作为一款监控指标的度量类库,提供了许多工具帮助开发者来完成自定义的监控工作。

使用Metrics

通过构建一个Spring Boot的基本应用来演示Metrics的工作方式。

在Maven的pom.xml中引入Metrics

<dependency> <groupId>io.dropwizard.metricsgroupId> <artifactId>metrics-coreartifactId> <version>${metrics.version}version> dependency> 

目前Metrics的最新版本是3.1.2

Metrics的基本工具

Metrics提供了五个基本的度量类型:

  1. Gauges(度量)
  2. Counters(计数器)
  3. Histograms(直方图数据)
  4. Meters(TPS计算器)
  5. Timers(计时器)

MetricsMetricRegistry是中心容器,它是程序中所有度量的容器,所有新的度量工具都要注册到一个MetricRegistry实例中才可以使用,尽量在一个应用中保持让这个MetricRegistry实例保持单例。

MetricRegistry 容器

在代码中配置好这个MetricRegistry容器:

@Bean public MetricRegistry metrics() { return new MetricRegistry(); } 

Meters TPS计算器

TPS计算器这个名称并不准确,Meters工具会帮助我们统计系统中某一个事件的速率。比如每秒请求数(TPS),每秒查询数(QPS)等等。这个指标能反应系统当前的处理能力,帮助我们判断资源是否已经不足。Meters本身是一个自增计数器。

通过MetricRegistry可以获得一个Meter

@Bean public Meter requestMeter(MetricRegistry metrics) { return metrics.meter("request"); } 

在请求中调用mark()方法,来增加计数,我们可以在不同的请求中添加不同的Meter,针对自己的系统完成定制的监控需求。

@RequestMapping("/hello") @ResponseBody public String helloWorld() { requestMeter.mark(); return "Hello World"; } 

应用运行的过程中,在console中反馈的信息:

-- Meters ----------------------------------------------------------------------
request
             count = 21055
         mean rate = 133.35 events/second
     1-minute rate = 121.66 events/second
     5-minute rate = 36.99 events/second
    15-minute rate = 13.33 events/second

从以上信息中可以看出Meter可以为我们提供平均速率,以及采样后的1分钟,5分钟,15分钟的速率。

Histogram 直方图数据

直方图是一种非常常见的统计图表,Metrics通过这个Histogram这个度量类型提供了一些方便实时绘制直方图的数据

和之前的Meter相同,我们可以通过MetricRegistry来获得一个Histogram

@Bean public Histogram responseSizes(MetricRegistry metrics) { return metrics.histogram("response-sizes"); } 

在应用中,需要统计的位置调用Histogramupdate()方法。

responseSizes.update(new Random().nextInt(10)); 

比如我们需要统计某个方法的网络流量,通过Histogram就非常的方便。

在console中Histogram反馈的信息:

-- Histograms ------------------------------------------------------------------
response-sizes
             count = 21051 min = 0 max = 9 mean = 4.55 stddev = 2.88 median = 4.00 75% <= 7.00 95% <= 9.00 98% <= 9.00 99% <= 9.00 99.9% <= 9.00 

Histogram为我们提供了最大值,最小值和平均值等数据,利用这些数据,我们就可以开始绘制自定义的直方图了。

Counter 计数器

Counter的本质就是一个AtomicLong实例,可以增加或者减少值,可以用它来统计队列中Job的总数。

通过MetricRegistry也可以获得一个Counter实例。

@Bean public Counter pendingJobs(MetricRegistry metrics) { return metrics.counter("requestCount"); } 

在需要统计数据的位置调用inc()dec()方法。

// 增加计数 pendingJobs.inc(); // 减去计数 pendingJobs.dec(); 

console的输出非常简单:

-- Counters --------------------------------------------------------------------
requestCount
             count = 21051

只是输出了当前度量的值。

Timer 计时器

Timer是一个MeterHistogram的组合。这个度量单位可以比较方便地统计请求的速率和处理时间。对于接口中调用的延迟等信息的统计就比较方便了。如果发现一个方法的RPS(请求速率)很低,而且平均的处理时间很长,那么这个方法八成出问题了。

同样,通过MetricRegistry获取一个Timer的实例:

@Bean public Timer responses(MetricRegistry metrics) { return metrics.timer("executeTime"); } 

在需要统计信息的位置使用这样的代码:

final Timer.Context cOntext= responses.time(); try { // handle request } finally { context.stop(); } 

console中就会实时返回这个Timer的信息:

-- Timers ----------------------------------------------------------------------
executeTime
             count = 21061 mean rate = 133.39 calls/second 1-minute rate = 122.22 calls/second 5-minute rate = 37.11 calls/second 15-minute rate = 13.37 calls/second min = 0.00 milliseconds max = 0.01 milliseconds mean = 0.00 milliseconds stddev = 0.00 milliseconds median = 0.00 milliseconds 75% <= 0.00 milliseconds 95% <= 0.00 milliseconds 98% <= 0.00 milliseconds 99% <= 0.00 milliseconds 99.9% <= 0.01 milliseconds 

Gauges 度量

除了Metrics提供的几个度量类型,我们可以通过Gauges完成自定义的度量类型。比方说很简单的,我们想看我们缓存里面的数据大小,就可以自己定义一个Gauges

metrics.register( MetricRegistry.name(ListManager.class, "cache", "size"), (Gauge<Integer>) () -> cache.size() ); 

这样Metrics就会一直监控Cache的大小。

除此之外有时候,我们需要计算自己定义的一直单位,比如消息队列里面消费者(consumers)消费的速率生产者(producers)的生产速率的比例,这也是一个度量。

public class CompareRatio extends RatioGauge { private final Meter consumers; private final Meter producers; public CacheHitRatio(Meter consumers, Meter producers) { this.cOnsumers= consumers; this.producers = producers; } @Override protected Ratio getRatio() { return Ratio.of(consumers.getOneMinuteRate(), producers.getOneMinuteRate()); } } 

把这个类也注册到Metrics容器里面:

@Bean public CompareRatio cacheHitRatio(MetricRegistry metrics, Meter requestMeter, Meter producers) { CompareRatio compareRatio = new CompareRatio(consumers, producers); metrics.register("生产者消费者比率", compareRatio); return cacheHitRatio; } 

Reporter 报表

Metrics通过报表,将采集的数据展现到不同的位置,这里比如我们注册一个ConsoleReporterMetricRegistry中,那么console中就会打印出对应的信息。

@Bean public ConsoleReporter consoleReporter(MetricRegistry metrics) { return ConsoleReporter.forRegistry(metrics) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); } 

除此之外Metrics还支持JMXHTTPSlf4j等等,可以访问 http://metrics.dropwizard.io/3.1.0/manual/core/#reporters 来查看Metrics提供的报表,如果还是不能满足自己的业务,也可以自己继承Metrics提供的ScheduledReporter类完成自定义的报表类。

完整的代码

这个demo是在一个很简单的spring boot下运行的,关键的几个类完整代码如下。

配置类MetricConfig.java

package demo.metrics.config; import com.codahale.metrics.*; import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.concurrent.TimeUnit; @Configuration public class MetricConfig { @Bean public MetricRegistry metrics() { return new MetricRegistry(); } /** * Reporter 数据的展现位置 * * @param metrics * @return */ @Bean public ConsoleReporter consoleReporter(MetricRegistry metrics) { return ConsoleReporter.forRegistry(metrics) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); } @Bean public Slf4jReporter slf4jReporter(MetricRegistry metrics) { return Slf4jReporter.forRegistry(metrics) .outputTo(LoggerFactory.getLogger("demo.metrics")) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .build(); } @Bean public JmxReporter jmxReporter(MetricRegistry metrics) { return JmxReporter.forRegistry(metrics).build(); } /** * 自定义单位 * * @param metrics * @return */ @Bean public ListManager listManager(MetricRegistry metrics) { return new ListManager(metrics); } /** * TPS 计算器 * * @param metrics * @return */ @Bean public Meter requestMeter(MetricRegistry metrics) { return metrics.meter("request"); } /** * 直方图 * * @param metrics * @return */ @Bean public Histogram responseSizes(MetricRegistry metrics) { return metrics.histogram("response-sizes"); } /** * 计数器 * * @param metrics * @return */ @Bean public Counter pendingJobs(MetricRegistry metrics) { return metrics.counter("requestCount"); } /** * 计时器 * * @param metrics * @return */ @Bean public Timer responses(MetricRegistry metrics) { return metrics.timer("executeTime"); } } 

接收请求的类MainController.java

package demo.metrics.action; import com.codahale.metrics.Counter; import com.codahale.metrics.Histogram; import com.codahale.metrics.Meter; import com.codahale.metrics.Timer; import demo.metrics.config.ListManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.Random; @Controller @RequestMapping("/") public class MainController { @Autowired private Meter requestMeter; @Autowired private Histogram responseSizes; @Autowired private Counter pendingJobs; @Autowired private Timer responses; @Autowired private ListManager listManager; @RequestMapping("/hello") @ResponseBody public String helloWorld() { requestMeter.mark(); pendingJobs.inc(); responseSizes.update(new Random().nextInt(10)); listManager.getList().add(1); final Timer.Context cOntext= responses.time(); try { return "Hello World"; } finally { context.stop(); } } } 

项目启动类DemoApplication.java

package demo.metrics; import com.codahale.metrics.ConsoleReporter; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ApplicationContext; import java.util.concurrent.TimeUnit; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(DemoApplication.class, args); // 启动Reporter ConsoleReporter reporter = ctx.getBean(ConsoleReporter.class); reporter.start(1, TimeUnit.SECONDS); } } 

这里再配合InfluxdbGrafana可以构建一个非常漂亮的实时监控界面。


Grafana监控界面

采集数据(Metrics)-> 存储数据(InfluxDB) -> 显示数据(Grafana)。

资源有限,我把这一套服务搭建在了一台CentOS 7的服务器上。

安装influxdb

InfluxDB是Go语言写的一个时序型数据库,可以通过rpm的方式来安装它,这里最好能安装InfluxDB的最新版本,否则跟Grafana的交互会有一些不兼容。

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

安装完成之后,启动并查看这个服务是否在正常运行:

systemctl start influxdb.service
[root@metrics ~]# systemctl status influxdb.service ● influxdb.service - InfluxDB is an open-source, distributed, time series database Loaded: loaded (/usr/lib/systemd/system/influxdb.service; enabled; vendor preset: disabled) Active: active (running) since 一 2016-04-25 17:50:04 CST; 1 day 1h ago Docs: https://docs.influxdata.com/influxdb/ Main PID: 17871 (sh) CGroup: /system.slice/influxdb.service ├─17871 /bin/sh -c /usr/bin/influxd -config /etc/influxdb/influxdb.conf >>/dev/nul... └─17872 /usr/bin/influxd -config /etc/influxdb/influxdb.conf 4月 25 17:50:04 metrics systemd[1]: Started InfluxDB is an open-source, distributed...se. 4月 25 17:50:04 metrics systemd[1]: Starting InfluxDB is an open-source, distribute...... Hint: Some lines were ellipsized, use -l to show in full.

启动后打开 web 管理界面 http://192.168.2.183:8083/ 默认用户名和密码是 root 和 root. InfluxDB 的 Web 管理界面端口是 8083,HTTP API 监听端口是 8086,如果需要更改这些默认设定,修改 InfluxDB 的配置文件(/etc/influxdb/influxdb.conf)并重启就可以了。

安装 Grafana

Grafana是一个非常好看的监控界面,它的安装方式也非常简单,通过yum,一条命令就可以在server上完成安装。

yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta51460725904.x86_64.rpm

完成安装之后,启动并检查它的状态:

[root@metrics ~]# systemctl start grafana-server.service [root@metrics ~]# systemctl status grafana-server.service ● grafana-server.service - Starts and stops a single grafana instance on this system Loaded: loaded (/usr/lib/systemd/system/grafana-server.service; disabled; vendor preset: disabled) Active: active (running) since 一 2016-04-25 09:37:07 CST; 1 day 10h ago Docs: http://docs.grafana.org Main PID: 10309 (grafana-server) CGroup: /system.slice/grafana-server.service └─10309 /usr/sbin/grafana-server --cOnfig=/etc/grafana/grafana.ini --pidfile= cfg:d...

用浏览器访问 Grafana,默认端口是3000,默认的帐号密码都是 admin(可以在配置文件中找到),登录之后配置数据库


设置数据源

Metrics Reporter

之前提到Metrics只需要配置它的Reporter就可以输出到对应的地方,对于Influxdb,在github上找到了一个InfluxdbReporter(https://github.com/davidB/metrics-influxdb)。

Maven中引入:

<dependency> <groupId>com.github.davidbgroupId> <artifactId>metrics-influxdbartifactId> <version>0.8.2version> dependency>

并在代码中配置Influxdb的数据源:

@Bean(name = "influxdbReporter") public ScheduledReporter influxdbReporter(MetricRegistry metrics) throws Exception { return InfluxdbReporter.forRegistry(metrics) .protocol(InfluxdbProtocols.http("host_ip_address", port, "username", "password", "database")) .convertRatesTo(TimeUnit.SECONDS) .convertDurationsTo(TimeUnit.MILLISECONDS) .filter(MetricFilter.ALL) .skipIdleMetrics(false) .build(); }

启动项目之后,我们开始配置我们需要看到的图表信息:


配置图标信息

最后我们利用wrk测试工具并发访问连接:

➜  ~ wrk -t 10 -c 50 -d 5s http://127.0.0.1:8888/hello Running 5s test @ http://127.0.0.1:8888/hello 10 threads and 50 connections Thread Stats Avg Stdev Max +/- Stdev Latency 6.59ms 12.17ms 210.05ms 92.16% Req/Sec 1.40k 427.51 2.79k 71.80% 69902 requests in 5.04s, 10.28MB read Requests/sec: 13873.71 Transfer/sec: 2.04MB

于此同时Grafana界面上系统实时的数据信息也展现出来了:


实时监控画面

 

转载:https://www.jianshu.com/p/e4f70ddbc287


推荐阅读
  • iOS超签签名服务器搭建及其优劣势
    本文介绍了搭建iOS超签签名服务器的原因和优势,包括不掉签、用户可以直接安装不需要信任、体验好等。同时也提到了超签的劣势,即一个证书只能安装100个,成本较高。文章还详细介绍了超签的实现原理,包括用户请求服务器安装mobileconfig文件、服务器调用苹果接口添加udid等步骤。最后,还提到了生成mobileconfig文件和导出AppleWorldwideDeveloperRelationsCertificationAuthority证书的方法。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • 本文讨论了如何使用Web.Config进行自定义配置节的配置转换。作者提到,他将msbuild设置为详细模式,但转换却忽略了带有替换转换的自定义部分的存在。 ... [详细]
  • 基于Socket的多个客户端之间的聊天功能实现方法
    本文介绍了基于Socket的多个客户端之间实现聊天功能的方法,包括服务器端的实现和客户端的实现。服务器端通过每个用户的输出流向特定用户发送消息,而客户端通过输入流接收消息。同时,还介绍了相关的实体类和Socket的基本概念。 ... [详细]
  • 本文介绍了如何在Azure应用服务实例上获取.NetCore 3.0+的支持。作者分享了自己在将代码升级为使用.NET Core 3.0时遇到的问题,并提供了解决方法。文章还介绍了在部署过程中使用Kudu构建的方法,并指出了可能出现的错误。此外,还介绍了开发者应用服务计划和免费产品应用服务计划在不同地区的运行情况。最后,文章指出了当前的.NET SDK不支持目标为.NET Core 3.0的问题,并提供了解决方案。 ... [详细]
  • 本文探讨了容器技术在安全方面面临的挑战,并提出了相应的解决方案。多租户保护、用户访问控制、中毒的镜像、验证和加密、容器守护以及容器监控都是容器技术中需要关注的安全问题。通过在虚拟机中运行容器、限制特权升级、使用受信任的镜像库、进行验证和加密、限制容器守护进程的访问以及监控容器栈,可以提高容器技术的安全性。未来,随着容器技术的发展,还需解决诸如硬件支持、软件定义基础设施集成等挑战。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • GAMETECH腾讯云游戏行业技术沙龙成都站圆满落幕
    11月13日,由腾讯云主办、游戏茶馆协办的2020年首场GAME-TECH腾讯云游戏行业技术沙龙在成都圆满落幕。本次沙龙邀请了腾讯云游戏行业解决方案总监宋永周、腾讯云游戏行业高级解决方案架构师曾梓恩、腾讯云游戏行业高级产品架构师郑晓曦、腾讯云游戏行业高级解决方案架构师温球良和天美L1(王者荣耀)服务器技术副总监杨光,为参会同行们带来了干货满满的技术建议。本文介绍了腾讯云游戏云的优势和为不同游戏研运场景提供的服务。腾讯云在中国游戏云服务市场领跑,成为众多游戏开发者的合作伙伴。 ... [详细]
  • 如何查询zone下的表的信息
    本文介绍了如何通过TcaplusDB知识库查询zone下的表的信息。包括请求地址、GET请求参数说明、返回参数说明等内容。通过curl方法发起请求,并提供了请求示例。 ... [详细]
author-avatar
十分风格的功夫_723
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有