繁体   English   中英

使用Dropwizard指标报告JVM的CPU使用情况

[英]Reporting JVM's CPU usage with Dropwizard metrics

我使用Dropwizard指标来衡量我的应用程序中的各种指标。 它们是JVM工具中的几个预定义报告 ,但奇怪的是我找不到任何报告CPU使用情况。

我可以创建自己的Gauge(使用getThreadCpuTime或类似),但我最好的猜测是我错过了一些东西。

我是否在当前的实施中错过了它,还是比我初想的更复杂?

我对Dropwizard了解不多,但我过去曾使用ThreadMXBean来提供可扩展分布式计算系统中CPU利用率的估算,因此我将分享我认为与该问题相关的内容。 事情肯定比他们第一次看起来更复杂:

ThreadMxBean有点误导......

ThreadMxBean.getThreadCpuTime(id)仅返回自线程启动以来特定线程在CPU上执行代码所花费的时间(以纳秒为单位)。 它没有提供有关您的线程可能被阻塞或等待(休眠)多长时间的信息,因此它并不能让您对CPU使用情况有所了解。 您还需要测量总阻塞/等待时间,然后在程序运行时间内跟踪所有这三个值以跟踪CPU使用情况。 奇怪的是, ThreadMXBean没有直接获取阻塞/等待时间的方法,所以你可能会想要放弃。

...但你可以用它来获取一个ThreadInfo对象......

首先,要启用它,请调用这两行(如果您的JVM不支持,则可能会抛出异常):

ManagementFactory.getThreadMXBean().setThreadCpuTimeEnabled(true);
ManagementFactory.getThreadMXBean().setThreadContentionMonitoringEnabled(true);

现在,您可以调用ThreadMXBean.getThreadInfo(threadId)来获取与特定线程对应的ThreadInfo实例。 此info对象有两个方法getBlockedTime()getWaitedTime() ,它们返回线程在这两种状态中花费的总毫秒数。 没有getCpuTime()方法(如果你问我,这个对象是一个非常愚蠢的缺点),但如果你知道你的线程何时启动,你可以这样做:

//Initialized somewhere else:
ThreadMXBean bean = ...
long threadStartTime = System.currentTimeMillis();
Thread myThread = ...

//Inside your metrics-gathering code:
long now = System.currentTimeMillis();
ThreadInfo info = bean.getThreadInfo(myThread.getId());
long totalCpuTime = now - (info.getBlockedTime()+info.getWaitedTime()+threadStartTime);

现在,您可以按百分比计算线程利用率。

我们差不多了,但我们还没完成。 每次我们浏览上面发布的代码的最后三行时,我们只收集执行/阻塞/等待状态的总时间。 要计算百分比,我们需要跟踪收集这些指标的时间,以便我们知道自上次指标更新以来线程在每个状态中花费了多少时间。 所以,做这样的事情:

class ThreadUsageMetrics{
    long timestamp, totalBlockedTime, totalWaitTime;

    ThreadUsageMetrics(long ts, long blocked, long wait){
        timestamp = ts;
        totalBlockedTime = blocked;
        totalWaitTime = wait;
    }

    double computeCpuUsageSince(ThreadUsageMetrics prev){
        long time = timestamp - prev.timestamp;
        long blocked = totalBlockedTime - prev.totalBlockedTime;
        long waited = totalWaitTime - prev.totalWaitTime;
        return (time-(blocked+waited))/(double)time;
    }
}

这将使我们在0.0到1.0的范围内加倍,表示CPU使用率占自上次度量标准更新以来总时间的百分比。 我假设您可以将此值转换为百分比,并每隔5秒左右将其提供给Dropwizard的Gauge实例。 在我的项目中,这就是我们几年来估计CPU使用率的方式,它对我们来说非常有用。

关于此的几点注意事项 - 我们实际上并不需要在此对象中明确存储总CPU时间,因为任何时间都没有花费在阻塞或等待上的时间是执行时间,或者是在上下文切换期间花费的时间。 我们无法知道上下文切换时间,但可以安全地假设在99.9%的情况下总上下文切换时间可以忽略不计。

这里有一点需要注意 - 我们并没有真正衡量CPU使用率。

如果您仔细阅读,您会注意到我说我们正在“估算”CPU使用率。 我这说的原因是我们正在测量特定Java Thread总执行时间。 Java没有提供实际CPU硬件使用的概念 - 它只是线程执行所花费的总时间。 超级线程之类的东西更加混乱,“执行”所花费的时间实际上意味着等待另一个线程从ALU或内存总线上下来所花费的时间。 我认为这可以很好地衡量代码在物理硬件线程上运行的时间,但是如果您想要测量实际的CPU使用率,那么您将无法在纯Java中执行此操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM