在本模块中,我将把几个常用的监控部分给梳理一下。前面我们提到过,在性能监控图谱中,有操作系统、应用服务器、中间件、队列、缓存、数据库、网络、前端、负载均衡、Web 服务器、存储、代码等很多需要监控的点。显然这些监控点不能在一个专栏中全部覆盖并一一细化,我只能找最常用的几个,做些逻辑思路的说明,同时也把具体的实现描述出来。如果你遇到了其他的组件,也需要一一实现这些监控。

在本篇中,主要想说明白下图的这个监控逻辑。

这应该是现在最流行的一套监控逻辑了吧。我今天把常见的使用 Grafana、Prometheus、InfluxDB、Exporters 的数据展示方式说一下,如果你刚进入性能测试领域,也能有一个感性的认识。

有测试工具,有监控工具,才能做后续的性能分析和瓶颈定位,所以有必要把这些工具的逻辑跟你摆一摆。

所有做性能的人都应该知道一点,不管数据以什么样的形式展示,最要紧的还是看数据的来源和含义,以便做出正确的判断。

我先说明一下 JMeter 和 node_exporter 到 Grafana 的数据展示逻辑。至于其他的 Exporter,我就不再解释这个逻辑了,只说监控分析的部分。

JMeter+InfluxDB+Grafana 的数据展示逻辑

一般情况下,我们用 JMeter 做压力测试时,都是使用 JMeter 的控制台来查看结果。如下图所示:

或者装个插件来看结果:

或者用 JMeter 来生成 HTML:

这样看都没有问题,我们在前面也强调过,对于压力工具来说,我们最多只关心三条曲线的数据:TPS(T 由测试目标定义)、响应时间、错误率。这里的错误率还只是辅助排查问题的曲线,没有问题时,只看 TPS 和响应时间即可。

不过采取以上三种方式有几个方面的问题。

  1. 整理结果时比较浪费时间。
  2. 在 GUI 用插件看曲线,做高并发时并不现实。
  3. 在场景运行时间比较长的时候,采用生成 HTML 的方式,会出现消耗内存过大的情况,而实际上,在生成的结果图中,有很多生成的图我们并不是那么关注。
  4. 生成的结果保存之后再查看比较麻烦,还要一个个去找。

那么如何解决这几个问题呢?

用 JMeter 的 Backend Listener 帮我们实时发送数据到 InfluxDB 或 Graphite 可以解决这样的问题。

Graphite Backend Listener 的支持是在 JMeter 2.13 版本,InfluxdDB Backend Listener 的支持是在 JMeter 3.3 的版本,它们都是用异步的方式把数据发送出来,以便查看。

其实有这个 JMeter 发送给 InfluxDB 的数据之后,我们不需要看上面的那些 HTML 数据,也可以直观地看到系统性能的性能趋势。

并且这样保存下来的数据,在测试结束后想再次查看也比较方便比对。

JMeter+InfluxDB+Grafana 的结构如下:

在这个结构中,JMeter 发送压力到服务器的同时,统计下 TPS、响应时间、线程数、错误率等信息。默认每 30 秒在控制台输出一次结果(在 jmeter.properties 中有一个参数 #summariser.interval=30 可以控制)。

配置了 Backend Listener 之后,将统计出的结果异步发送到 InfluxDB 中。最后在 Grafana 中配置 InfluxDB 数据源和 JMeter 显示模板。

然后就可以实时查看 JMeter 的测试结果了,这里看到的数据和控制台的数据是一样。

但如果这么简单就说完了,这篇文章也就没价值了。下面我们来说一下,数据的传输和展示逻辑。

JMeter 中 Backend Listener 的配置

下面我们就 InfluxDB 的 Backend Listener 做个说明。它的配置比较简单,在脚本中加上即可。

我们先配置好 influxdb Url、application 等信息,application 这个配置可以看成是场景名。

那么 JMeter 如何将数据发给 InfluxDB 呢?请看源码中的关键代码,如下所示:

    private void addMetrics(String transaction, SamplerMetric metric) {
// FOR ALL STATUS
addMetric(transaction, metric.getTotal(), metric.getSentBytes(), metric.getReceivedBytes(), TAG_ALL, metric.getAllMean(), metric.getAllMinTime(),
metric.getAllMaxTime(), allPercentiles.values(), metric::getAllPercentile);
// FOR OK STATUS
addMetric(transaction, metric.getSuccesses(), null, null, TAG_OK, metric.getOkMean(), metric.getOkMinTime(),
metric.getOkMaxTime(), okPercentiles.values(), metric::getOkPercentile);
// FOR KO STATUS
addMetric(transaction, metric.getFailures(), null, null, TAG_KO, metric.getKoMean(), metric.getKoMinTime(),
metric.getKoMaxTime(), koPercentiles.values(), metric::getKoPercentile);


metric.getErrors().forEach((error, count) -> addErrorMetric(transaction, error.getResponseCode(),
error.getResponseMessage(), count));
}

从这段代码可以看出,站在全局统计的视角来看,这里把 JMeter 运行的统计结果,比如事务的 Total 请求、发送接收字节、平均值、最大值、最小值等,都加到 metric 中,同时也会把成功和失败的事务信息添加到 metric 中去。

在源码中,还有更多的添加 metric 的步骤,你有兴趣的话,也可以看一下 JMeter 源码中的InfluxdbBackendListenerClient.java。

保存了 metric 之后,再使用 InfluxdbMetricsSender 发送到 Influxdb 中去。发送关键代码如下:

   @Override
public void writeAndSendMetrics() {
........
if (!copyMetrics.isEmpty()) {
try {
if(httpRequest == null) {
httpRequest = createRequest(url);
}
StringBuilder sb = new StringBuilder(copyMetrics.size()*35);
for (MetricTuple metric : copyMetrics) {
// Add TimeStamp in nanosecond from epoch ( default in InfluxDB )
sb.append(metric.measurement)
.append(metric.tag)
.append(" ") //$NON-NLS-1$
.append(metric.field)
.append(" ")
.append(metric.timestamp+"000000")
.append("\n"); //$NON-NLS-1$
} StringEntity entity = new StringEntity(sb.toString(), StandardCharsets.UTF_8); httpRequest.setEntity(entity);
lastRequest = httpClient.execute(httpRequest, new FutureCallback<HttpResponse>() {
@Override
public void completed(final HttpResponse response) {
int code = response.getStatusLine().getStatusCode();
/*
* HTTP response summary 2xx: If your write request received
* HTTP 204 No Content, it was a success! 4xx: InfluxDB
* could not understand the request. 5xx: The system is
* overloaded or significantly impaired.
*/
if (MetricUtils.isSuccessCode(code)) {
if(log.isDebugEnabled()) {
log.debug("Success, number of metrics written: {}", copyMetrics.size());
}
} else {
log.error("Error writing metrics to influxDB Url: {}, responseCode: {}, responseBody: {}", url, code, getBody(response));
}
}
@Override
public void failed(final Exception ex) {
log.error("failed to send data to influxDB server : {}", ex.getMessage());
}
@Override
public void cancelled() {
log.warn("Request to influxDB server was cancelled");
}
});
........
}
}
}

通过 writeAndSendMetrics,就将所有保存的 metrics 都发给了 InfluxDB。

InfluxDB 中的存储结构

然后我们再来看下 InfluxDB 中如何存储:

> show databases
name: databases
name
----
_internal
jmeter
> use jmeter
Using database jmeter
>
> show MEASUREMENTS
name: measurements
name
----
events
jmeter
> select * from events where application='7ddemo'
name: events
time application text title
---- ----------- ---- -----
1575255462806000000 7ddemo Test Cycle1 started ApacheJMeter
1575256463820000000 7ddemo Test Cycle1 ended ApacheJMeter
..............
n> select * from jmeter where application='7ddemo' limit 10
name: jmeter
time application avg count countError endedT hit max maxAT meanAT min minAT pct90.0 pct95.0 pct99.0 rb responseCode responseMessage sb startedT statut transaction
---- ----------- --- ----- ---------- ------ --- --- ----- ------ --- ----- ------- ------- ------- -- ------------ --------------- -- -------- ------ -----------
1575255462821000000 7ddemo 0 0 0 0 0 internal
1575255467818000000 7ddemo 232.82352941176472 17 0 17 849 122 384.9999999999996 849 849 0 0 all all
1575255467824000000 7ddemo 232.82352941176472 17 849 122 384.9999999999996 849 849 0 0 all 0_openIndexPage
1575255467826000000 7ddemo 232.82352941176472 17 849 122 384.9999999999996 849 849 ok 0_openIndexPage
1575255467829000000 7ddemo 0 1 1 1 1 internal
1575255472811000000 7ddemo 205.4418604651163 26 0 26 849 122 252.6 271.4 849 0 0 all all
1575255472812000000 7ddemo 0 1 1 1 1 internal
1575255472812000000 7ddemo 205.4418604651163 26 849 122 252.6 271.4 849 ok 0_openIndexPage
1575255472812000000 7ddemo 205.4418604651163 26 849 122 252.6 271.4 849 0 0 all 0_openIndexPage
1575255477811000000 7ddemo 198.2142857142857 27 0 27 849 117 263.79999999999995 292.3500000000001 849 0 0 all all

这段代码也就是说,在 InfluxDB 中,创建了两个 MEASUREMENTS,分别是 events 和 jmeter。这两个各自存了数据,我们在界面中配置的 testtile 和 eventTags 放在了 events 这个 MEASUREMENTS 中。在模板中这两个值暂时都是不用的。

在 jmeter 这个 MEASUREMENTS 中,我们可以看到 application 和事务的统计信息,这些值和控制台一致。在 Grafana 中显示的时候,就是从这个表中取出的数据,根据时序做的曲线。

性能监控工具之Grafana+Prometheus+Exporters的更多相关文章

  1. 性能测试之数据库监控分析工具Grafana+Prometheus

    使用到 Grafana+Prometheus+Mysql_exportor 使用Prometheus和Grafana,可以快速的构建我们性能测试的绝大多数的监控模型:数据库监控.服务器监控.Jvm监控 ...

  2. Grafana+Prometheus打造全方位立体监控系统

    前言 本文主要介绍如何使用Grafana和Prometheus以及node_exporter对Linux服务器性能进行监控.下面两张图分别是两台服务器监控信息: 服务器A 服务器B 概述 Promet ...

  3. 你值得拥有:25个Linux性能监控工具

    一.基于命令行的性能监控工具 1.dstat - 多类型资源统计工具 该命令整合了vmstat,iostat和ifstat三种命令.同时增加了新的特性和功能可以让你能及时看到各种的资源使用情况,从而能 ...

  4. 深入理解JVM—性能监控工具

    (转自:http://yhjhappy234.blog.163.com/blog/static/31632832201222691738865/) 我们知道,在JVM编译期和加载器,甚至运行期已经做了 ...

  5. CentOS 7上的性能监控工具

    Linux中基于命令行的性能监控工具:dstat.top.netstat.vmstat.htop.ss.glances 1.dstat – 多类型资源统计工具(需配置epel源) 该命令整合了vmst ...

  6. 25个Linux性能监控工具

    一段时间以来,我们在网上向读者介绍了如何为Linux以及类Linux操作系统配置多种不同的性能监控工具.在这篇文章中我们将罗列一系列使用最频繁的性能监控工具,并对介绍到的每一个工具提供了相应的简介链接 ...

  7. (转载)Java自带的GUI性能监控工具Jconsole以及JisualVM简介

    原文链接:http://blog.csdn.net/chendc201/article/details/22905503 1 Jconsole 1.1 简介以及连接 JConsole是一个基于JMX的 ...

  8. JProfiler - Java的性能监控工具

    简介 JProfiler是一款Java的性能监控工具.可以查看当前应用的对象.对象引用.内存.CPU使用情况.线程.线程运行情况(阻塞.等待等),同时可以查找应用内存使用得热点,即:哪个对象占用的内存 ...

  9. 深入理解JVM(七)——性能监控工具

    前言 工欲善其事必先利其器,性能优化和故障排查在我们大都数人眼里是件比较棘手的事情,一是需要具备一定的原理知识作为基础,二是需要掌握排查问题和解决问题的流程.方法.本文就将介绍利用性能监控工具,帮助开 ...

随机推荐

  1. windows核心编程-第一章 对程序错误的处理

    第一章-对程序错误的处理 在开始介绍Microsoft Windows 的特性之前,必须首先了解 Wi n d o w s的各个函数是如何进行错误处理的. 当调用一个Wi n d o w s函数时,它 ...

  2. 【JavaScript】JS从入门到深入(复习查漏向

    [JavaScript]JS从入门到深入(复习查漏向 pre 精细得学过一遍JS后才发现,原来之前CTF中有些nodejs的题目以及一些游戏题的payload就变得很好理解了. 基础知识 ECMASc ...

  3. Day008 三种初始化及内存分析

    三种初始化和内存分析 Java内存分析: 堆: 存放new的对象和数组. 可以被所有的线程共享,不会存放别的对象引用. 栈: 存放基本变量类型(会包含这个基本类型的具体数值). 引用对象的变量(会存放 ...

  4. 多线程-2.线程创建方式和Thread类

    线程的创建方式 1.继承Thread类,重写run方法,示例如下: 1 class PrimeThread extends Thread { 2 long minPrime; 3 PrimeThrea ...

  5. 拦截器(Interceptor)与过滤器(Filter)

    目录 用户的普通Http请求执行顺序 过滤器.拦截器添加后的执行顺序 拦截器(Interceptor)的基本定义 拦截器(Interceptor)必须实现的三个方法 单个拦截器(Interceptor ...

  6. PostgreSQL实现字符串拼接

      在日常工作中会遇到将多行的值拼接为一个值展现,如果使用过Oracle数据库,可以使用list_agg的聚合函数来实现.那么PostgreSQL也有这样的功能,函数为string_agg.具体用法如 ...

  7. linux操作系统故障处理-ext4文件系统超级块损坏修复

    linux操作系统故障处理-ext4文件系统超级块损坏修复   背景 前天外面出差大数据测试环境平台有7台服务器挂了,同事重启好了五台服务器,但是还有两台服务器启动不起来,第二天回来后我和同事再次去机 ...

  8. KVM 添加新硬件

    1 显卡 spice 2视频 qxl驱动 3 声音 ich6最好  ich9最清楚 4 输入 鼠标 智能图   否则不能VNC找不到焦点 5 磁盘大小 至少80G 否则 无法自动安装  无swap和 ...

  9. PECcpu2006中执行单个测试程序的方法

    PECcpu2006中执行单个测试程序的方法 2010-12-30 11:44:00 maray 阅读数 10055更多 分类专栏: 科学理论   版权声明:本文为博主原创文章,遵循CC 4.0 BY ...

  10. JDK版本升级

    背景:本来安装了一个1.6版本的JDK,因为版本过低需要升级成1.8 安装过程很简单一路next,主要是遇到几个问题需要备注一下解决方法. Error opening registry key'sof ...