本文主要基于 SkyWalking 3.2.6 正式版
1. 概述
2. Agent 收集 JVM 指标
- 2.1 JVMService
- 2.2 CPU
- 2.3 Memory
- 2.4 MemoryPool
- 2.5 GC
3. Collector 存储 JVM 指标
- 3.1 JVMMetriCSServiceHandler
- 3.2 CPU
- 3.3 Memory
- 3.4 MemoryPool
- 3.5 GC
4. 心跳
666. 彩蛋
RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
您对于源码的疑问每条留言都将得到认真回复甚至不知道如何读源码也可以请教噢
新的源码解析文章实时收到通知每周更新一篇左右
认真的源码交流微信群
1. 概述
本文主要分享 SkyWalking JVM 指标的收集与存储大体流程如下:
Agent 每秒定时收集 JVM 指标到缓冲队列
Agent 每秒定时将缓冲队列的 JVM 指标发送到 Collector
Collector 接收到 JVM 指标, 异步批量存储到存储器( 例如, ES )
目前 JVM 指标包括四个维度:
- CPU
- Memory
- MemoryPool
- GC
SkyWalking UI 界面如下:
2. Agent 收集 JVM 指标
- 2.1 JVMService
- org.skywalking.apm.agent.core.jvm.JVMService
, 实现 BootService Runnable 接口, JVM 指标服务, 负责将 JVM 指标收集并发送给 Collector 代码如下:
queue 属性, 收集指标队列
collectMetricFuture 属性, 收集指标定时任务
sendMetricFuture 属性, 发送指标定时任务
sender 属性, 发送器
#beforeBoot() 方法, 初始化 queue ,sender 属性, 并将自己添加到 GRPCChannelManager , 从而监听与 Collector 的连接状态
boot 方法, 创建两个定时任务:
第 88 至 90 行: 创建收集指标定时任务, 0 秒延迟, 1 秒间隔, 调用 JVMService#run() 方法
第 92 至 94 行: 创建发送指标定时任务, 0 秒延迟, 1 秒间隔, 调用 Sender#run() 方法
2.1.1 定时收集
JVMService#run() 方法, 代码如下:
第 110 至 111 行: 应用实例注册后, 才收集 JVM 指标
第 116 至 122 行: 创建 JVMMetric 对象
第 118 行: 调用
CPUProvider#getCpuMetric()
方法, 获得 GC 指标
第 119 行: 调用
MemoryProvider#getMemoryMetricList()
方法, 获得 Memory 指标
第 120 行: 调用
MemoryPoolProvider#getMemoryPoolMetricList()
方法, 获得 MemoryPool 指标
第 121 行: 调用
GCProvider#getGCList()
方法, 获得 GC 指标
第 125 至 128 行: 提交 JVMMetric 对象到收集指标队列
2.1.2 定时发送
JVMService.Sender , 实现 Runnable GRPCChannelListener 接口, JVM 指标发送器代码如下:
status 属性, 连接状态
stub 属性, 阻塞 Stub
#statusChanged(GRPCChannelStatus)
方法, 当连接成功时, 创建阻塞 Stub
#run() 方法, 代码如下:
第 148 至 151 行: 应用实例注册后, 并且连接中, 才发送 JVM 指标
第 153 至 155 行: 调用
#drainTo(Collection)
方法, 从队列移除所有 JVMMetric 到 buffer 数组
第 157 至 162 行: 使用 Stub , 批量发送到 Collector
- 2.2 CPU
- org.skywalking.apm.agent.core.jvm.cpu.CPUProvider
,CPU 提供者, 提供 #getCpuMetric() 方法, 采集 CPU 指标, 如下图所示:
usagePercent :JVM 进程占用 CPU 百分比
第 51 行: 调用
CPUMetricAccessor#getCPUMetric()
方法, 获得 CPU 指标
在 CPUProvider 构造方法 中, 初始化 cpuMetricAccessor 数量, 代码如下:
第 37 行: 调用
ProcessorUtil#getNumberOfProcessors()
方法, 获得 CPU 数量
第 40 至 42 行: 创建 SunCpuAccessor 对象
第 44 至 46 行: 发生异常, 说明不支持, 创建 NoSupportedCPUAccessor 对象
为什么需要使用
ClassLoader#loadClass(className)
方法呢? 因为 SkyWalking Agent 是通过 JavaAgent 机制, 实际未引入, 所以通过该方式加载类
- 2.2.1 CPUMetricAccessor
- org.skywalking.apm.agent.core.jvm.cpu.CPUMetricAccessor
,CPU 指标访问器抽象类代码如下:
lastCPUTimeNs 属性, 获得进程占用 CPU 时长, 单位: 纳秒
lastSampleTimeNs 属性, 最后采样时间, 单位: 纳秒
cpuCoreNum 属性, CPU 数量
- #init() 方法, 初始化 lastCPUTimeNs lastSampleTimeNs
- #getCpuTime() 抽象方法, 获得 CPU 占用时间, 由子类完成
- #getCPUMetric() 方法, 获得 CPU 指标放在和 SunCpuAccessor 一起分享这里我先记得, JVM 进程占用 CPU 率的计算公式:
进程 CPU 占用总时间 / ( 进程启动总时间 * CPU 数量)
CPUMetricAccessor 有两个子类, 实际上文我们已经看到它的创建:
SunCpuAccessor , 基于 SUN 提供的方法, 获取 CPU 指标访问器
NoSupportedCPUAccessor , 不支持的 CPU 指标访问器因此, 使用该类的情况下, 获取不到具体的进程 CPU 占用率
SunCpuAccessor 构造方法 , 代码如下:
第 32 行: 设置 CPU 数量
第 33 行: 获得 OperatingSystemMXBean 对象通过该对象, 在 #getCpuTime() 实现方法, 调用
OperatingSystemMXBean#getProcessCpuTime()
方法, 获得 JVM 进程占用 CPU 总时长
- long getProcessCpuTime()
- Returns the CPU time used by the process on which the Java virtual machine is running in nanoseconds. The returned value is of nanoseconds precision but not necessarily nanoseconds accuracy. This method returns -1 if the the platform does not support this operation.
- Returns:
- the CPU time used by the process in nanoseconds, or -1 if this operation is not supported.
第 34 行: 调用 #init() 方法, 初始化 lastCPUTimeNs lastSampleTimeNs
#getCPUMetric() 方法, 获得 CPU 指标代码如下:
第 58 至 59 行: 获得 JVM 进程占用 CPU 总时长
第 64 行:
now - lastSampleTimeNs
, 获得 JVM 进程启动总时长
这里为什么相减呢? 因为 CPUMetricAccessor 不是在 JVM 启动时就进行计算, 通过相减, 解决偏差
第 63 至 64 行: 计算 JVM 进程占用 CPU 率
- 2.3 Memory
- org.skywalking.apm.agent.core.jvm.memory.MemoryProvider
,Memory 提供者, 提供
#getMemoryMetricList()
方法, 采集 Memory 指标, 如下图所示:
MemoryUsage
Java 中监控程序内存的函数
JVM 内存调优相关的一些笔记(杂)
isHeap : 是否堆内内存
init : 初始化的内存数量
max : 最大的内存数量
used : 已使用的内存数量
committed : 可以使用的内存数量
第 44 至 51 行: 使用 MemoryMXBean 对象, 获得堆内 ( Heap ) 内存
第 54 至 61 行: 使用 MemoryMXBean 对象, 获得非堆内 ( None-Heap ) 内存
- 2.4 MemoryPool
- org.skywalking.apm.agent.core.jvm.memorypool.MemoryPoolProvider
,MemoryPool 提供者, 提供
#getMemoryPoolMetricList()
方法, 采集 MemoryPool 指标数组, 如下图:
- 2.4.1 MemoryPoolMetricAccessor
- org.skywalking.apm.agent.core.jvm.memorypool.MemoryPoolMetricAccessor
- 2.4.2 MemoryPoolModule
- org.skywalking.apm.agent.core.jvm.memorypool.MemoryPoolModule
- #getPermNames()
- #getCodeCacheNames()
- #getEdenNames()
- #getOldNames()
- #getSurvivorNames()
- #getMetaspaceNames()
- CMSCollectorModule
- G1CollectorModule
- ParallelCollectorModule
- SerialCollectorModule
- #getMemoryPoolMetricList()
- 2.5.1 GCMetricAccessor
- org.skywalking.apm.agent.core.jvm.gc.GCMetricAccessor
- 2.5.2 GCModule
- org.skywalking.apm.agent.core.jvm.gc.GCModule
- #getOldGCName()
- #getNewGCName()
- CMSGCModule
- G1GCModule
- ParallelGCModule
- SerialGCModule
- #getGCList() 实现方法, 代码如下:
- 3.2 CPU
- org.skywalking.apm.collector.storage.table.jvm.CpuMetric
- 3.3 Memory
- org.skywalking.apm.collector.storage.table.jvm.MemoryMetric
- 3.4 MemoryPool
- org.skywalking.apm.collector.storage.table.jvm.MemoryPoolMetric
- 3.5 GC
- org.skywalking.apm.collector.storage.table.jvm.GCMetric
来源: http://www.suo.im/1NFPss