nGrinder二次开发之监控机器性能数据_neven7的博客-程序员宝宝_ngrinder monitor内存指标

技术标签: 性能测试  

1.背景

做性能测试时,统计性能数据分为被压系统的数据和被压系统所在机器的数据,被压系统所在机器的数据主要包括CPU利用率、内存使用率、网络IO、磁盘IO和负载load;nGrinder默认只收集CPU, Memory, Received Byte/s, Sent Byte Per Secode/s,同时支持自定义数据收集,之前介绍过相关内容:nGrinder对监控机器收集自定义数据及源码分析

展示自定义数据需定时的写文件,比较麻烦;本文将介绍如何改动源码,直接展示CPU利用率、内存使用率、网络IO、磁盘IO和负载load这5类数据。

2.实现

nGrinder是通过sigar api统计机器性能数据,sigar项目主页:https://support.hyperic.com/display/SIGAR/Home, sigar api :http://cpansearch.perl.org/src/DOUGM/hyperic-sigar-1.6.3-src/docs/javadoc/org/hyperic/sigar/package-summary.html

2-1.新增数据类型

ngrinder-core中package:org.ngrinder.monitor.share.domain下SystemInfo类定义了收集的数据类型,新增load、read、write和memUsedPercentage数据字段:

/**
* modify by hugang
*/
public class SystemInfo extends MonitorInfo implements Serializable {
    

    private static final long serialVersionUID = -2995334644975166549L;

    /**
     * Header field of monitor status fields.
     */
    // 新增load、磁盘IO和内存使用率
    public static final String HEADER = "ip,system,collectTime,freeMemory,"
            + "totalMemory,cpuUsedPercentage,receivedPerSec,sentPerSec,load,read,write,memUsedPercentage";

    public boolean isParsed() {
        return true;
    }

    /**
     * Enum for the system type, linux or windows.
     */
    public enum System {
        LINUX, WINDOW
    }

    private System system;

    // 网络IO
    protected BandWidth bandWidth;

    private long totalCpuValue;

    private long idleCpuValue;

    private long freeMemory;

    private long totalMemory;

    private float cpuUsedPercentage;


    // load
    private double load;

    // 磁盘读
    private long read;

    // 磁盘写
    private long write;


    // 内存使用率
    private double memUsedPercentage;


    ...
    set()、get()方法


    public void parse(CompositeData cd) {
          // 新增
            this.load = getDouble(cd, "load");
            this.write = getLong(cd, "write");
            this.read = getLong(cd, "read");
            this.memUsedPercentage = getDouble(cd, "memUsedPercentage"); 
    }

    public String toRecordString() {
        StringBuilder sb = new StringBuilder();
        sb.append(ip).append(",").append(system).append(",");
        sb.append(DateUtils.getCollectTimeInLong(new Date(getCollectTime()))).append(",").append(freeMemory).append(",");

        sb.append(totalMemory).append(",").append(cpuUsedPercentage);
        if (bandWidth != null) {
            sb.append(",").append(bandWidth.getReceivedPerSec()).append(",").append(bandWidth.getSentPerSec());
        } 
        // 新类型load、read、write、memUsedPercentage数据拼接
        sb.append(",").append(load).append(",").append(read).append(",").append(write).append(",").append(memUsedPercentage);
        if (customValues != null) {
            sb.append(",").append(customValues);
        }
        return sb.toString();
    }

public static class NullSystemInfo extends SystemInfo {
    
        private static final NullSystemInfo instance = new NullSystemInfo();

        public static SystemInfo getNullSystemInfo() {
            return instance;
        }

        /**
         * Return the empty record string.
         *
         * @return null filled record string.
         * @see #toRecordString()
         */
        @Override
        public String toRecordString() {
            StringBuilder sb = new StringBuilder();
            sb.append("null").append(",").append("null").append(",");
            sb.append("null").append(",").append("null").append(",");
            sb.append("null").append(",").append("null");
            if (bandWidth != null) {
                sb.append(",").append("null").append(",").append("null");
            }
            // 拼接新类型数据为"null"
            sb.append(",").append("null").append(",").append("null").append(",").append("null");
            if (customValues != null) {
                int valueCount = StringUtils.countMatches(customValues, ",") + 1;
                for (int i = 0; i < valueCount; i++) {
                    sb.append(",").append("null");
                }
            }
            return sb.toString();
        }

        public boolean isParsed() {
            return false;
        }
    }



}

2-2.收集新增数据

ngrinder-core中package:org.ngrinder.monitor.collector下SystemDataCollector类中execute()方法实现了系统数据的收集:

/**
* modify by hugang
*/
public synchronized SystemInfo execute() {
        SystemInfo systemInfo = new SystemInfo();
        systemInfo.setCollectTime(System.currentTimeMillis());
        try {
            BandWidth networkUsage = getNetworkUsage();
            BandWidth bandWidth = networkUsage.adjust(prev.getBandWidth());
            systemInfo.setBandWidth(bandWidth);
            // getCombined()代表 Sum of User + Sys + Nice + Wait
            systemInfo.setCPUUsedPercentage((float) sigar.getCpuPerc().getCombined() * 100);
            Cpu cpu = sigar.getCpu();
            systemInfo.setTotalCpuValue(cpu.getTotal());
            systemInfo.setIdleCpuValue(cpu.getIdle());
            Mem mem = sigar.getMem();
            systemInfo.setTotalMemory(mem.getTotal() / 1024L);
            systemInfo.setFreeMemory(mem.getActualFree() / 1024L);

            // 新增load、磁盘IO和内存使用率
            // The system load averages for the past 1, 5, and 15 minutes.
            double load = 0;
            long read = 0l;
            long write = 0l;

            load = sigar.getLoadAverage()[0];

            //LOGGER.info("monitor system load:{}", load);

            // 所有的文件系统
            FileSystem[] fileSystems = sigar.getFileSystemList();
            // 获取本地文件系统
            List<String> localDevNames = new ArrayList<String>();
            for(FileSystem fileSystem : fileSystems) {
                if(fileSystem.getType() == FileSystem.TYPE_LOCAL_DISK) {
                    localDevNames.add(fileSystem.getDevName());
                }
            }


            for(String localDevName : localDevNames) {
                read += sigar.getDiskUsage(localDevName).getReadBytes();
                write += sigar.getDiskUsage(localDevName).getWriteBytes();
            }


            //LOGGER.info("monitor system read:{}, write:{}", read, write);

            systemInfo.setLoad(load);
            systemInfo.setRead(read / 1024L);
            systemInfo.setWrite(write / 1024L);
            systemInfo.setMemUsedPercentage(mem.getUsedPercent());

            systemInfo.setSystem(OperatingSystem.IS_WIN32 ? SystemInfo.System.WINDOW : SystemInfo.System.LINUX);
            systemInfo.setCustomValues(getCustomMonitorData());
        } catch (Throwable e) {
            LOGGER.error("Error while getting system perf data:{}", e.getMessage());
            LOGGER.debug("Error trace is ", e);
        }
        prev = systemInfo;
        return systemInfo;
    }

2-3.前端monitor模板

ngrinder-controller下src/main/webapp/WEB-INF/ftl/perftest/detail_report/monitor.ftl定义了系统数据的可视化,修改如下:

<#setting number_format="computer">
<#import "../../common/spring.ftl" as spring/>
<div class="page-header page-header">
    <h4>Monitor</h4>
</div>
<h6 id="cpu_usage_chart_header">CPU利用率(User + Sys + Nice + Wait),建议值:小于75%</h6>
<div class="chart" id="cpu_usage_chart"></div>
<h6 id="mem_usage_chart_header">Memory使用率,建议值:小于80%</h6>
<div class="chart" id="mem_usage_chart"></div>
<h6 id="received_byte_per_sec_chart_header">Received Byte Per Second</h6>
<div class="chart" id="received_byte_per_sec_chart"></div>
<h6 id="sent_byte_per_sec_chart_header">Sent Byte Per Second</h6>
<div class="chart" id="sent_byte_per_sec_chart"></div>

<h6 id="custom_monitor_chart_1_header">Load-average(one-minute)</h6>
<div class="chart" id="custom_monitor_chart_1"></div>
<h6 id="custom_monitor_chart_2_header">Physical Disk readBytes(total number of physical disk reads)</h6>
<div class="chart" id="custom_monitor_chart_2"></div>
<h6 id="custom_monitor_chart_3_header">Physical Disk writesBytes(total number of physical disk writes)</h6>
<div class="chart" id="custom_monitor_chart_3"></div>


<script>
    //@ sourceURL=/perftest/detail_report/monitor
    function getMonitorDataAndDraw(testId, targetIP) {
     
        var ajaxObj = new AjaxObj("/perftest/api/" + testId + "/monitor");
        ajaxObj.params = {
            targetIP: targetIP,
            imgWidth: parseInt($("#cpu_usage_chart").width())
        };
        ajaxObj.success = function (data) {
     
            var interval = data.chartInterval;


            // modify by hugang
            // data.customData1为load, data.customData2为磁盘读, data.customData3为磁盘写
            drawChart('cpu_usage_chart', [data.cpu], formatPercentage, interval);
              // 调整为内存使用率
            drawChart('mem_usage_chart', [data.customData4], formatPercentage, interval);
            // load
            drawChart("custom_monitor_chart_1", [data.customData1], formatDouble, interval);
            drawChart("received_byte_per_sec_chart", [data.received], formatNetwork, interval);
            drawChart("sent_byte_per_sec_chart", [data.sent], formatNetwork, interval);
            // 磁盘读
            drawChart("custom_monitor_chart_2", [data.customData2], formatMemory, interval);
            // 磁盘写
            drawChart("custom_monitor_chart_3", [data.customData3], formatMemory, interval);

            createChartExportButton("<@spring.message "perfTest.report.exportImg.button"/>", "<@spring.message "perfTest.report.exportImg.title"/>");
        };
        ajaxObj.call();
    }
    function drawChart(id, data, yFormat, interval) {
     
        return new Chart(id, data, interval, {yAxisFormatter: yFormat}).plot();
    }

    function drawOptionalChart(id, data, interval, labels) {
     
        var result = drawChart(id, data, interval, labels);
        if (result.isEmpty()) {
            $("#" + id).hide();
            $("#" + id + "_header").hide();
        }
    }
    getMonitorDataAndDraw(${id}, "${targetIP}");


</script>

3.结果展示

对工程进行打包:

hugangdeMacBook-Pro:CPC hugang$ mvn clean -Dmaven.test.skip=true package

部署新war包,服务正常启动后;需重新下载监控包,因为依赖的ngrinder-core.jar包有改动,重新启动监控服务后,执行性能测试任务。

系统监控数据文件:/root/.ngrinder/perftest/0_999/${任务id}/reportmonitor_system_${ip}.data新增load、read、write和memUsedPercentage。

前端展示:

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/neven7/article/details/53909256

智能推荐

用选择法对数组中10个整数按由小到大排序_____-7的博客-程序员宝宝_用选择法对数组中10个整数按由小到大排序

#include #include int main(){  void sort(int a[],int n);  int a[10],i;  printf("输入数组:\n");  for(i=0;i    scanf("%d",&a[i]);  sort(a,10);  printf("排序为:\n");  for(i=0;i    printf("

Flutter 自定义缩放控件_StoneHui_的博客-程序员宝宝_flutter 缩放

最近在学习 Flutter,俗话说的好,纸上得来终觉浅,所以动手撸了一个 gank.io 的 APP,有兴趣的可以 到 GitHub 看看源码。本文将与大家分享项目中自定义的缩放控件 GestureZoomBox 。功能双击缩放。双指缩放。以双击位置/双指位置作为缩放中心。限制缩放/拖动范围,超过范围自动回弹。作为父级 Widget 直接嵌套,无侵入。核心原理手势识别Ge...

组件库建设大纲__ZEUS___的博客-程序员宝宝

先梳理清楚一个组件库应该具备哪些能力?1.团队性,团队开发人员用最小学习代价可以加入开发队伍。2.易发布,组件库开发完成后应该可以一键构建并发布,自动生成更新日志。3.业务易接入,输出开发文档便于业务开发人员使用。基于上面的结论,应该需要以下几个命令dev运行本地开发环境。启动一个本地服务器,用于在开发过程中对文档和示例进行预览。build构建组件库。build-site构建文档站点。release发布组件库,发布前会自动执行 build 和 changelog 命令,并发布包。

如何使用Phantom系统构建和维护软件测试环境_housichao的博客-程序员宝宝

var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");document.write(unescape("%3Cscript src=" + gaJsHost + "google-analytics.com/ga.js type=text/javascript

转载:IOS 进入前台后台调用方法说明_qimuya的博客-程序员宝宝

原文链接:原文 一、挂起当有电话进来或者锁屏,这时你的应用程会挂起,在这时,UIApplicationDelegate委托会收到通知,调用 applicationWillResignActive 方法,你可以重写这个方法,做挂起前的工作,比如关闭网络,保存数据。C代码 1. - (void)applicationWillResignActive:(UIApplication*)applicat

130825组队赛-Regionals 2012, North America - East Central NA_Bright-xl的博客-程序员宝宝

A.Babs' Box Boutique一道简单的dfs搜索题,需要两两比较,然后搜到底,得到最大值就行了。比赛时队友写的,我只负责debug。。赛后自己写的。。#include#include#include#include#include#include#include#include#include#define mem(a,b) memset(a,b,sizeof

随便推点

单词精确查找_故园归梦的博客-程序员宝宝

#include &lt;stdio.h&gt;#include &lt;string.h&gt;int main(){ char str[100]; gets(str); char word[100]; gets(word); int count=0,j=0; for ( int i = 0; i &lt; strlen(str); i++ ) { while(str[i]==' ') { i++; } for ( int k = i; k &lt; i+str.

postman设置域名_Postman中文文档——证书(Certificates)_行走的饺子的博客-程序员宝宝

证书Postman的本地应用程序提供了一种在每个域名的基础上查看和设置SSL证书的方法。要管理客户端证书,请单击工具栏右侧的扳手图标,选择设置(Settings),然后选择证书(Certificates)选项卡。证书选项卡添加客户端证书要添加新的客户端证书,请单击添加证书(Add Certificate)链接。在 主机 (Host) 输入框,输入要使用该证书的请求URL的域名(无协议),例如,ec...

CentOS7下OpenLDAP+PhpLdapAdmin基本安装_酷林~的博客-程序员宝宝_phpldapadmin支持php7吗

本次实验参考链接:https://blog.csdn.net/weixin_41004350/article/details/89521170https://blog.csdn.net/mayancheng7/article/details/105753846实验中也因为自己的不仔细踩了不少坑,仅以此笔记记录一下。万分感谢两位大佬????CentOS7下OpenLDAP+PhpLdapAdmin基本安装1.安装openldap#yum安装软件[[email protected] ~]#

和菜头_《写给应届毕业生的99条箴言》读书笔记_阿正的梦工坊的博客-程序员宝宝

李世政的读书笔记 书名 《你不重要,你的喜欢很重要》 作者 和菜头 出版社 阅读日期 2019年五月十三日 书籍提纲 《写给应届毕业生的99条人生箴言》 ...

python中的赋值运算符_hcsdf123的博客-程序员宝宝_python中的赋值运算符

Python中的运算符主要有:=、+=、-=、*=、/=、//=、**=、%=具体如图:一、几个需要注意的运算符1、%,表示求膜,也就是余数的意思,如图:当n=4时和当n=5时2、/和//的区别,/是求商,而//是求整除商,如图:3、*和**的区别,*表示乘以某个数,而**是多少个n相乘,如图:4、假设n=4,当n+=1,则n=n+1             当n-=1就是n=n-1       ...

8086/8088 寻址方式补充篇_NIUZI_J的博客-程序员宝宝

作者:黑剑 出处:http://www.cnblogs.com/blacksword/ 8086/8088 寻址方式补充篇上一节讲述了8086/8088 CPU寻址方式,通过了解它的寻址方式会使得今后学习8086/8088汇编语言指令变得更加容易,因为汇编语言中大多数的指令就是对数据进行处理和运算。但是看完上一节内容,不仅没有让人觉得有所收获,反而增添了

推荐文章

热门文章

相关标签