JVM Profiler IOProfiler

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 开篇 IOProfiler因为采集方法的限制,目前支持linux系统指标采集,但是不支持mac,windows等操作系统。 IOProfiler通过读取linux系统的/proc/self/io的当前线程的IO指标数据,该文件的内容如下图所示,通过解析成kv键值对完成采集。

开篇

 IOProfiler因为采集方法的限制,目前支持linux系统指标采集,但是不支持mac,windows等操作系统。
 IOProfiler通过读取linux系统的/proc/self/io的当前线程的IO指标数据,该文件的内容如下图所示,通过解析成kv键值对完成采集。

[root@fuck logs]# cat /proc/3172/io 
rchar: 598796271
wchar: 160798214
syscr: 3124807
syscw: 5936285
read_bytes: 307200
write_bytes: 134148096
cancelled_write_bytes: 184320

 IOProfiler主要通过读取linux系统的/proc/stat来采集CPU的占用情况,该文件的内容如下图所示,通过解析成kv键值对完成采集。

[root@fuck logs]# cat /proc/stat
cpu  31965686 7863 22816368 10760846905 384719 21810 2723823 367110 0
cpu0 17337496 2161 12060256 2664404859 353464 21810 2715822 192461 0
cpu1 4445423 1896 3619627 2699436652 8995 0 3255 58954 0
cpu2 4421192 2028 3525381 2699115834 12552 0 2743 58589 0
cpu3 5761574 1776 3611102 2697889558 9706 0 2002 57104 0


源码分析

IO指标

  • ProcFileUtils.getProcIO()完成IO指标采集。
  • ProcFileUtils.getProcStatCpuTime()完成CPU指标采集。
  • 将采集结果组装成Map后进行上报
    public synchronized void profile() {
        Map<String, String> procMap = ProcFileUtils.getProcIO();
        Long rchar = ProcFileUtils.getBytesValue(procMap, "rchar");
        Long wchar = ProcFileUtils.getBytesValue(procMap, "wchar");
        Long read_bytes = ProcFileUtils.getBytesValue(procMap, "read_bytes");
        Long write_bytes = ProcFileUtils.getBytesValue(procMap, "write_bytes");

        List<Map<String, Object>> cpuTime = ProcFileUtils.getProcStatCpuTime();
        
        Map<String, Object> map = new HashMap<String, Object>();

        map.put("epochMillis", System.currentTimeMillis());
        map.put("name", getProcessName());
        map.put("host", getHostName());
        map.put("processUuid", getProcessUuid());
        map.put("appId", getAppId());

        if (getTag() != null) {
            map.put("tag", getTag());
        }

        if (getCluster() != null) {
            map.put("cluster", getCluster());
        }
        
        if (getRole() != null) {
            map.put("role", getRole());
        }

        Map<String, Object> selfMap = new HashMap<String, Object>();
        map.put("self", selfMap);
        
        Map<String, Object> ioMap = new HashMap<String, Object>();
        selfMap.put("io", ioMap);

        ioMap.put("rchar", rchar);
        ioMap.put("wchar", wchar);
        ioMap.put("read_bytes", read_bytes);
        ioMap.put("write_bytes", write_bytes);

        map.put("stat", cpuTime);
        
        if (reporter != null) {
            reporter.report(PROFILER_NAME, map);
        }
    }

IO指标采集

  • 通过解析/proc/self/io文件来完成数据采集。
  • 通过简单的kv解析来完成数据的采集。
    private static final String PROC_SELF_IO_FILE = "/proc/self/io";

    public static Map<String, String>  getProcIO() {
        return getProcFileAsMap(PROC_SELF_IO_FILE);
    }

    public static Map<String, String> getProcFileAsMap(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists() || file.isDirectory() || !file.canRead()) {
                return Collections.emptyMap();
            }

            Map<String, String> result = new HashMap<>();
            List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
            for (String line : lines) {
                int index = line.indexOf(VALUE_SEPARATOR);
                if (index <= 0 || index >= line.length() - 1) {
                    continue;
                }
                String key = line.substring(0, index).trim();
                String value = line.substring(index + 1).trim();
                result.put(key, value);
            }
            return result;
        } catch (Throwable ex) {
            logger.warn("Failed to read file " + filePath, ex);
            return Collections.emptyMap();
        }
    }

CPU指标

  • 通过读取文件/proc/stat来完成数据采集。
  • 通过解析带cpu开头的数据来完成数据采集。
    private static final String PROC_STAT_FILE = "/proc/stat";


    public static List<Map<String, Object>> getProcStatCpuTime() {
        List<String[]> rows = getProcFileAsRowColumn(PROC_STAT_FILE);
        return getProcStatCpuTime(rows);
    }


    public static List<String[]> getProcFileAsRowColumn(String filePath) {
        try {
            File file = new File(filePath);
            if (!file.exists() || file.isDirectory() || !file.canRead()) {
                return Collections.emptyList();
            }
            // 获取文件的所有行,每行的保存格式是List<String[]>
            List<String[]> result = new ArrayList<>();
            List<String> lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8);
            // 遍历所有行,每一行以空格进行切割
            for (String line : lines) {
                result.add(line.split("\\s+"));
            }
            return result;
        } catch (Throwable ex) {
            logger.warn("Failed to read file " + filePath, ex);
            return Collections.emptyList();
        }
    }

    public static List<Map<String, Object>> getProcStatCpuTime(Collection<String[]> rows) {
        if (rows == null) {
            return Collections.emptyList();
        }
        
        final int minValuesInRow = 6;

        List<Map<String, Object>> result = new ArrayList<>();
        
        for (String[] row : rows) {
            if (row.length >= minValuesInRow && row[0].toLowerCase().startsWith("cpu")) {
                Map<String, Object> map = new HashMap<>();
                try {
                    map.put("cpu", row[0]);
                    map.put("user", Long.parseLong(row[1].trim()));
                    map.put("nice", Long.parseLong(row[2].trim()));
                    map.put("system", Long.parseLong(row[3].trim()));
                    map.put("idle", Long.parseLong(row[4].trim()));
                    map.put("iowait", Long.parseLong(row[5].trim()));
                    result.add(map);
                } catch (Throwable ex) {
                    continue;
                }
            }
        }
        
        return result;
    }


采集结果

{
    "stat": [],
    "appId": null,
    "name": "2343@xiaozhideMacBook-Pro.local",
    "host": "local",
    "processUuid": "d32879c3-3ebb-4228-a649-2821c369a30d",
    "self": {
        "io": {
            "wchar": null,
            "write_bytes": null,
            "rchar": null,
            "read_bytes": null
        }
    },
    "epochMillis": 1536102327045,
    "tag": "mytag"
}
目录
相关文章
|
分布式计算 监控 Java
Uber jvm profiler 使用
Uber jvm profiler 使用
287 0
Uber jvm profiler 使用
|
存储 SQL 分布式计算
如何用 Uber JVM Profiler 等可视化工具监控 Spark 应用程序?
  关键要点   持续可靠地运行 Spark 应用程序是一项具有挑战性的任务,而且需要一个良好的性能监控系统。   - 在设计性能监控系统时有三个目标——收集服务器和应用程序指标、在时序数据库中存储指标,并提供用于数据可视化的仪表盘。   Uber JVM Profiler 被用于监控 Spark 应用程序,用到的其他技术还有 InfluxDB(用于存储时序数据)和 Grafana(数据可视化工具)。性能监控系统可帮助 DevOps 团队有效地监控系统,用以满足应用程序的合规性和 SLA。
271 0
|
监控 Java 调度
JVM Profiler 启动过程分析
开篇  先来调侃一句,原来独角兽Uber的程序员写的代码也是看得懂的,而且还是比较容易看得懂的,所以有时候在设计模式和代码结构清晰以及可读性方面我还是更倾向于后者,宁可重复或浪费一部分代码也要整个代码的可读性更强一些。
1157 0
|
Java
JVM Profiler CpuAndMemoryProfiler
开篇   CpuAndMemoryProfiler主要用来采集cpu和memory相关的信息,采集核心方法都是由ManagementFactory提供的接口: getClassLoadingMXBean() 返回 Java 虚拟机的类加载系统的管理 Bean。
893 0
|
Java
JVM Profiler StacktraceCollectorProfiler
开篇  StacktraceCollectorProfiler主要用来采集线程的调用栈,原理是通过ManagementFactory.getThreadMXBean()返回的ThreadMXBean对象来实现。
820 0
|
监控 Java 编解码
JVM Profiler 方法耗时采集
开篇  JVM Profile的方法采集通过修改字节码在原来方法体的前置和后置增加采集耗时的代码。核心是基于基于java自带的instrument包和javassist包来实现的。
1181 0
|
NoSQL Java Redis
JVM Profiler Reporter介绍
开篇  JVM Profiler采集完数据后可以通过多种途径上报数据,对接Console,File,redis,kafka等,这篇文章会把源码罗列一下毕竟都很简单。
1174 0
|
消息中间件 分布式计算 Java
JVM Profiler介绍
开篇  过去的几周把java多线程相关部分的源码粗粗的看了一遍基本上也算告一段落了,后面应该会聚焦看下dubbo、mycat、datax以及剩下部分的mybatis。
1716 0
|
监控 Java 消息中间件
JVM Profiler 整体架构
开篇 整个JVM Profiler的组件类似于上图,抽象出来主要分为:Class File Transformer:负责转换被监控方法的字节码,在前后增加耗时统计。
1060 0
|
1月前
|
存储 安全 Java
jvm 锁的 膨胀过程?锁内存怎么变化的
【10月更文挑战第3天】在Java虚拟机(JVM)中,`synchronized`关键字用于实现同步,确保多个线程在访问共享资源时的一致性和线程安全。JVM对`synchronized`进行了优化,以适应不同的竞争场景,这种优化主要体现在锁的膨胀过程,即从偏向锁到轻量级锁,再到重量级锁的转变。下面我们将详细介绍这一过程以及锁在内存中的变化。
37 4