likes
comments
collection
share

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

作者站长头像
站长
· 阅读数 11

前提介绍

在应用在线上运行时,经常需要处理大量的数据。在业务代码中,我们通常会非常关注某些方法的调用次数和响应时间等信息。这种场景通常需要使用metrics统计来实现。为了实现这样的功能,我们可以使用现有的度量工具库,而不必自己编写度量插件。其中,一个常用的度量工具库是Dropwizard Metrics。

Dropwizard Metrics

Dropwizard Metrics是一个用于度量、聚合和报告应用程序性能指标的开源库。它提供了一组简单而强大的API,用于收集各种指标数据,并且支持将这些数据进行聚合和报告。

使用Dropwizard Metrics可以轻松地在业务代码中添加度量统计,从而了解方法的调用次数、响应时间等关键指标,并通过定制的报告机制进行监控和分析。

Dropwizard的特点

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

  • 多种度量类型:Dropwizard Metrics提供了多种度量类型,包括计数器(Counter)、计时器(Timer)、直方图(Histogram)和仪表盘(Gauge)。这些度量类型可以用来统计方法的调用次数、响应时间、数据分布等。

  • 可插拔的报告:Dropwizard Metrics支持将统计数据以不同的方式进行报告,包括控制台输出、日志文件、JMX,以及集成到其他监控系统(如Graphite、InfluxDB等)。

  • 线程安全性:Dropwizard Metrics的API设计考虑了多线程环境下的并发访问,确保在统计数据收集过程中的线程安全性。

  • 可扩展性:Dropwizard Metrics提供了插件机制,可以自定义度量器、报告器和过滤器,以满足特定的需求。

注意:在使用度量统计工具时,需要权衡好度量的粒度和对性能的影响,避免过度统计和监控导致性能问题。同时,也要注意保护用户隐私和数据安全,避免统计敏感信息。 .

Dropwizard的开发案例

Metrics是一个Java类库,提供了服务性能检测工具。它包含了功能强大的性能指标工具库,用于度量生产环境中各个关键组件的性能。

通过本篇文章将介绍Metrics提供的各种测量工具,以及如何使用这些工具以及它们何时派上用场的详细信息。

需要引入Maven依赖

为了使用Metrics库,您需要添加metrics-core库的依赖。

<!-- https://mvnrepository.com/artifact/io.dropwizard.metrics/metrics-core -->
<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-core</artifactId>
    <version>4.2.25</version>
</dependency>

常用度量类型

以下是一些常用的度量指标类型:

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

  • 【Meter(速率统计器)】:用于统计系统中某一事件的响应速率,例如每秒请求数(TPS)或每秒查询数(QPS)。该指标直接反映系统当前的处理能力。
  • 【Gauge(计量器)】:Gauges用来统计某个指标的瞬时值。
  • 【Counter(计数器)】:本质上是一个java.util.concurrent.atomic.LongAdder,用于计数。
  • 【Histogram(直方图)】:用于收集数据并生成直方图,用于分析数据的分布情况。
  • 【Timer(计时器)】:是Meter和Histogram的结合体,用于统计接口请求速率和响应时长。

Meter(每秒请求数为单位测量请求率)

计量器用于测量事件随时间变化的速率,例如"每秒请求数"。除了平均速率之外,流量计还可以跟踪1分钟、5分钟和15分钟的移动平均值。

以下是使用Meter组件的开发步骤,您可以按照以下步骤逐个进行开发和实现: 【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

定义度量核心MetricRegistry

Metrics的核心是MetricRegistry类,它是应用程序的所有指标的容器。

首先,我们需要定义并创建一个核心注册组件服务,用于管理和注册Metric度量组件。创建Metric度量组件实例:使用适当的构造函数或工厂方法创建Metric度量组件的实例。

  	/**
     * 1. 度量核心注册管理组件
     */
    public final MetricRegistry metricRegistry = new MetricRegistry();

您可能希望将其集成到应用程序的生命周期中(也许使用您的依赖项注入框架),但静态字段就可以了。

构建对应的Meter指标对象

为了实现服务应的采样控制机制,我们可以使用Meter对象。

  	/**
     * 2. 构建对应的Meter指标对象
     */
    private final Meter requests = metricRegistry.meter("demoMeter");

请求标记采样

请求标记采样是一种在服务应用程序中进行采样的技术,用于记录特定类型的请求。

 /**
     * 3. 请求标记采样
     * @param requestDelta
     */
    public void requestMark(Long requestDelta){
        if(Objects.isNull(requestDelta)){
            requests.mark();
        }
        requests.mark(requestDelta);
    }

业务方法控制

在这里,我们调用了requestMark操作来进行Meter的采样,并使用Thread.sleep方法来模拟业务操作的耗时。 当然,未来我们可以采用框架来处理这些操作,可以结合AOP(面向切面编程)来更方便地控制采样,同时也能减少对业务代码的侵入性。

 /**
     * 4. 业务方法控制
     */
    public void businessMethod(){
        System.out.println("business method execute start");
        try {
            requestMark(100L);
            Thread.sleep(300);
        System.out.println("business method execute stop");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

使用AOP可以将采样逻辑与业务逻辑分离,通过在切面中定义采样逻辑,可以更灵活地控制采样的时机和方式。这样可以使代码更加清晰和可维护,并且可以在不修改业务代码的情况下进行采样操作。

报告器

Metric的报告器的作用是将度量指标的数据输出到不同的目标,以便进行监控、分析和可视化。报告器可以将度量指标的数据以不同的形式进行报告,例如输出到控制台、写入日志文件、发送到远程监控系统等。报告器可以根据配置的频率或触发条件定期或实时地生成报告。 【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

报告器的作用

  • 监控和实时反馈:报告器可以将度量指标的数据输出到控制台或日志文件,使开发人员能够实时监控应用程序的性能和行为。
  • 性能分析和优化:通过将度量指标的数据输出到报告器,可以对应用程序的性能进行分析和优化。开发人员可以根据报告器生成的报告,识别性能瓶颈和优化机会。
  • 可视化和报表:报告器可以将度量指标的数据以图表或报表的形式进行展示,使数据更加直观和易于理解。这有助于团队成员和管理者对应用程序的性能和运行情

当然,您也可以自己实现一个定制化的报告器,以满足特定的需求并实现自定义的可视化效果。在我们接下来的案例中,为了方便演示,我们使用了ConsoleReporter作为示例报告器。ConsoleReporter将度量指标的数据输出到控制台,提供了简单而直观的可视化效果。

ConsoleReporter报告器

ConsoleReporter是Metrics库提供的一个报告器,用于将度量指标输出到控制台。在这个方法中,我们使用forRegistry方法创建一个ConsoleReporter对象。

定义输出控制组件

定义了一个名为consolePrint的方法。该方法的功能是创建一个ConsoleReporter对象,并使用metricRegistry作为其注册表。

   void consolePrint() {
        ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);
    }

通过convertRatesTo和convertDurationsTo方法将度量指标的速率单位设置为秒和间隔时间单位设置为毫秒。 【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南) 它的继承关系如下所示: 【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南) 此外i,还有其他的继承实现类,例如:Slf4jReporter和CsvReporter,后面我会单独出一篇文章进行分析和介绍说明。

实际案例

public class MeterDemo {

    /**
     * 1. 度量核心注册管理组件
     */
    public final MetricRegistry metricRegistry = new MetricRegistry();

    /**
     * 2. 构建对应的Meter指标对象
     */
    private final Meter requests = metricRegistry.meter("demoMeter");

    /**
     * 3. 请求标记采样
     * @param requestDelta
     */
    public void requestMark(Long requestDelta){
        if(Objects.isNull(requestDelta)){
            requests.mark();
        }
        requests.mark(requestDelta);
    }

    /**
     * 4. 业务方法控制
     */
    public void businessMethod(){
        System.out.println("business method execute start");
        try {
            for(int i = 0; i < 10; i++){
                requestMark(10L);
                Thread.sleep(300);
            }
        System.out.println("business method execute stop");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }


    public static void main(String[] args) {
        // 分配模拟多个线程,进行处理执行业务方法
        MeterDemo meterDemo = new MeterDemo();
        meterDemo.consolePrint();
        Executors.newFixedThreadPool(3).
                execute(meterDemo::businessMethod);
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

     void consolePrint() {
        ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);
    }
}

除了统计每分钟的请求数之外,还默认支持移动平均,统计5分钟,15分钟和全部的平均每分钟请求数。如下面的结果所示。

2024/2/3 下午12:49:28 ============================================================

-- Meters ----------------------------------------------------------------------
demoMeter
             count = 100
         mean rate = 16.36 events/second
     1-minute rate = 20.00 events/second
     5-minute rate = 20.00 events/second
    15-minute rate = 20.00 events/second
  • count = 100:表示在统计周期内,共记录了100个事件。
  • mean rate = 16.36 events/second:表示在统计周期内,平均每秒发生了91.29个事件。这个指标反映了系统的整体处理速率。
  • 1-minute rate = 20.00 events/second:表示在过去的1分钟内,每秒发生的事件数量为20.00 。这个指标反映了最近1分钟内的事件发生速率。
  • 5-minute rate = 20.00 events/second:表示在过去的5分钟内,每秒发生的事件数量为20.00 。这个指标反映了最近5分钟内的事件发生速率。
  • 15-minute rate = 20.00 events/second:表示在过去的15分钟内,每秒发生的事件数量为20.00 。这个指标反映了最近15分钟内的事件发生速率。

Gauge(计量器)用于提供自定义度量

Gauge是对某一数值的瞬时测量。它可以用于测量任何可以返回一个数值的指标。例如,我们可以使用Gauge来测量队列中挂起的作业数。

  • MetricRegistry的核心注册对象都是相同的实现效果,因此,后面就不再多做赘述,我们侧重于指标度量本身进行分析。

  • 定义输出控制组件,ConsoleReporter是Metrics库提供的一个报告器,用于将度量指标输出到控制台,后面就不再多做赘述,我们侧重于指标度量本身进行分析。

创建Gauge指标对象

在MetricRegistry中注册的每个度量都需要一个唯一的名称。为了方便生成这些名称,可以使用MetricRegistry的name方法,下面便是源码MetricRegistry类中的name方法的实现。

public static String name(String name, String... names) {
        StringBuilder builder = new StringBuilder();
        append(builder, name);
        if (names != null) {
            String[] var3 = names;
            int var4 = names.length;

            for(int var5 = 0; var5 < var4; ++var5) {
                String s = var3[var5];
                append(builder, s);
            }
        }

        return builder.toString();
    }

    public static String name(Class<?> klass, String... names) {
        return name(klass.getName(), names);
    }

这两个方法的目的是帮助生成规范且唯一的度量名称。通过将多个名称组合起来,可以更好地组织和管理度量指标。

命名空间来生成一个唯一的名称

使用MetricRegistry的name方法可以帮助我们在注册度量时生成规范且唯一的名称,以便更好地组织和管理度量指标。

  • name(String name, String... names):方法的作用是将多个名称拼接成一个字符串。
  • name(Class klass, String... names):方法是对name(String name, String... names)方法的封装。它接受一个Class对象和多个名称作为参数,并将Class对象的名称作为第一个名称传递给name(String name, String... names)方法。
案例说明

MetricRegistry.name(xxx.class, "taskQueue", "capacity")方法,可以生成一个类似"xxx.taskQueue.capacity"的名称。在这个例子中,我们使用xxx.class,类作为命名空间,"taskQueue"作为第一个级别的名称,"capacity"作为第二个级别的名称。通过调用name方法,可以将这些部分组合成一个唯一的度量名称。

实现开发步骤

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

创建一个LinkedBlockingQueue
static final Queue<String> taskQueue = new LinkedBlockingQueue<>();
建立对应的业务方法存储队列元素以及拉取元素
    static void addTask(String task) {
        try {
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        taskQueue.add(task);
    }

    static void pullTask() {
        try {
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        taskQueue.poll();
    }
采样两个线程分别进行存储和拉取数据
 public static void main(String args[]) {
        // 开始启动打印输出报告组件
        consolePrint();
        // 注册一个Gauge指标
        metricRegistry.register(MetricRegistry.name(GaugeDemo.class, "taskQueue", "capacity"), (Gauge<Integer>) () -> taskQueue.size());
        // 定义添加元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                addTask(System.currentTimeMillis()+"");
            }
        }).start();
        // 定义拉取元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                pullTask();
            }
        }).start();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
数据结果
-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 0

-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 0
2024/2/3 下午3:04:11 =============================================================
-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 2

2024/2/3 下午3:04:12 =============================================================
-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 3

2024/2/3 下午3:04:13 =============================================================
-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 2

2024/2/3 下午3:04:14 =============================================================
-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 2
             
2024/2/3 下午3:04:15 =============================================================

-- Gauges ----------------------------------------------------------------------
metrics.GaugeDemo.taskQueue.capacity
             value = 1

Counter(计数器)

计数器是一个原子长整型实例,用于记录数量。您可以通过递增或递减计数器的值来跟踪某个事件的发生次数。例如,对于需要资源使用和释放的情况,计数器是一种更有效的方法。

计数器功能

  • 递增计数器:通过调用计数器的递增方法,可以将计数器的值增加1。
  • 递减计数器:通过调用计数器的递减方法,可以将计数器的值减少1。
  • 获取计数器的当前值:可以通过调用计数器的获取方法,获取计数器的当前值。
初始化MetricRegistry和ConsoleReporter的报告期
 static final MetricRegistry metricRegistry = new MetricRegistry();

 void consolePrint() {
        ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);
 }
Counter建议的开发案例

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

1. 创建Counter度量对象模型
    static final Counter counter = metricRegistry.counter(MetricRegistry.name("counter"));
2. 建立度量新增和递减的业务操作埋点
    public void incrNum(){
        try {
            counter.inc();
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public void decrNum(){
        try {
            counter.dec();
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
3. 采样两个线程分别进行不同速度下进行操作
    public static void main(String args[]) {
        // 开始启动打印输出报告组件
        CounterDemo counterDemo = new CounterDemo();
        counterDemo.consolePrint();
        // 定义添加元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                counterDemo.incrNum();
            }
        }).start();
        // 定义拉取元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                counterDemo.decrNum();
            }
        }).start();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

结果显示
2024/2/3 下午3:33:27 =============================================================

-- Counters --------------------------------------------------------------------
counter
             count = 2


2024/2/3 下午3:33:28 =============================================================

-- Counters --------------------------------------------------------------------
counter
             count = 5


2024/2/3 下午3:33:29 =============================================================

-- Counters --------------------------------------------------------------------
counter
             count = 5


2024/2/3 下午3:33:30 =============================================================

-- Counters --------------------------------------------------------------------
counter
             count = 3


2024/2/3 下午3:33:31 =============================================================

-- Counters --------------------------------------------------------------------
counter
             count = 0

Histograms(直方图)

直方图(Histogram)是一种用于统计数值分布情况的度量工具。除了常规的统计项(最小值、最大值、平均值),直方图还会统计一系列百分位点的数据,包括75th、90th、95th、98th、99th和99.9th百分位点。这些百分位点表示在数据集中,有多少比例的数据小于或等于该百分位点的值。

初始化Histogram对象模型

例如,我们新建一个Histgrom指标度量,我们统计以下对应的请求操作的耗费时间。

    private final Histogram responseSizes = metricRegistry.histogram(name(Hisgrom.class, "RT"));

执行耗时业务方法

public void exec(){
        try {
            long start = System.currentTimeMillis();
            Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
            long stop = System.currentTimeMillis();
            responseSizes.update(stop - start);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
}

实际案例调用效果

 public static void main(String args[]) {
        // 开始启动打印输出报告组件
        Hisgrom hisgrom = new Hisgrom();
        hisgrom.consolePrint();
        // 定义添加元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                hisgrom.exec();
            }
        }).start();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

结果信息

-- Histograms ------------------------------------------------------------------
metrics.Hisgrom.RT
             count = 2
               min = 329
               max = 681
              mean = 505.00
            stddev = 176.00
            median = 681.00
              75% <= 681.00
              95% <= 681.00
              98% <= 681.00
              99% <= 681.00
            99.9% <= 681.00


2024/2/3 下午3:54:44 =============================================================

-- Histograms ------------------------------------------------------------------
metrics.Hisgrom.RT
             count = 3
               min = 329
               max = 681
              mean = 542.03
            stddev = 152.48
            median = 615.00
              75% <= 681.00
              95% <= 681.00
              98% <= 681.00
              99% <= 681.00
            99.9% <= 681.00


2024/2/3 下午3:54:45 =============================================================

-- Histograms ------------------------------------------------------------------
metrics.Hisgrom.RT
             count = 7
               min = 172
               max = 779
              mean = 430.41
            stddev = 235.37
            median = 329.00
              75% <= 681.00
              95% <= 779.00
              98% <= 779.00
              99% <= 779.00
            99.9% <= 779.00


2024/2/3 下午3:54:46 =============================================================

-- Histograms ------------------------------------------------------------------
metrics.Hisgrom.RT
             count = 9
               min = 0
               max = 934
              mean = 438.70
            stddev = 304.16
            median = 329.00
              75% <= 681.00
              95% <= 934.00
              98% <= 934.00
              99% <= 934.00
            99.9% <= 934.00

通过统计这些百分位点,直方图可以提供更详细的数据分布情况,帮助我们了解数据的分散程度和异常值的存在。这对于性能分析和优化非常有用,可以帮助我们更好地理解数据的特征和行为。

Timers(计时器)

计时器(Timer)是一种用于测量调用特定代码的速率和持续时间分布的度量工具

通过使用计时器,我们可以深入了解代码的性能和执行时间分布,从而进行性能优化和故障排查。计时器是一种非常有用的度量工具,适用于需要测量代码执行速率和持续时间分布的场景。

计时器提供的特性

【深入浅出Java性能调优】「实战技术体系」详细分析探索Java服务器性能监控Metrics框架的实现原理分析(Dropwizard度量基础案例指南)

  • 调用速率:计时器可以测量特定代码被调用的速率,例如每秒调用次数(TPS)或每分钟调用次数(QPM)。这个指标可以帮助我们了解代码的执行频率和负载情况。

  • 持续时间分布:计时器可以测量特定代码的执行时间,并提供持续时间的分布情况。通过统计最小值、最大值、平均值以及一系列百分位点(如75th、90th、95th、98th、99th和99.9th),我们可以了解代码执行时间的分布情况,包括常见的执行时间和异常情况。

创建计时器Timer对象
private final Timer responses = metricRegistry.timer(name(TimerDemo.class, "RT"));

我们的是想方法和Histgrom直方图相同的执行代码案例:

public class TimerDemo {

    static final MetricRegistry metricRegistry = new MetricRegistry();

    void consolePrint() {
        ConsoleReporter reporter = ConsoleReporter.forRegistry(metricRegistry)
                .convertRatesTo(TimeUnit.SECONDS)
                .convertDurationsTo(TimeUnit.MILLISECONDS)
                .build();
        reporter.start(1, TimeUnit.SECONDS);
    }


     private final static Timer responseSizes = metricRegistry.timer(name(TimerDemo.class, "RT"));

    public void exec(){
        try {
            final Timer.Context context = responseSizes.time();
            try {
                long start = System.currentTimeMillis();
                Thread.sleep(ThreadLocalRandom.current().nextInt(1000));
                long stop = System.currentTimeMillis();
            } finally {
                context.stop();
            }

        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String args[]) {
        // 开始启动打印输出报告组件
        TimerDemo hisgrom = new TimerDemo();
        hisgrom.consolePrint();
        // 定义添加元素数据
        new Thread(()->{
            for(int i = 0 ; i<10 ; i++){
                hisgrom.exec();
            }
        }).start();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

结果

2024/2/3 下午4:12:10 =============================================================

-- Timers ----------------------------------------------------------------------
metrics.TimerDemo.RT
             count = 2
         mean rate = 1.85 calls/second
     1-minute rate = 0.00 calls/second
     5-minute rate = 0.00 calls/second
    15-minute rate = 0.00 calls/second
               min = 193.46 milliseconds
               max = 529.89 milliseconds
              mean = 362.94 milliseconds
            stddev = 168.22 milliseconds
            median = 529.89 milliseconds
              75% <= 529.89 milliseconds
              95% <= 529.89 milliseconds
              98% <= 529.89 milliseconds
              99% <= 529.89 milliseconds
            99.9% <= 529.89 milliseconds


2024/2/3 下午4:12:11 =============================================================

-- Timers ----------------------------------------------------------------------
metrics.TimerDemo.RT
             count = 5
         mean rate = 2.38 calls/second
     1-minute rate = 0.00 calls/second
     5-minute rate = 0.00 calls/second
    15-minute rate = 0.00 calls/second
               min = 27.93 milliseconds
               max = 792.14 milliseconds
              mean = 334.32 milliseconds
            stddev = 285.32 milliseconds
            median = 193.46 milliseconds
              75% <= 529.89 milliseconds
              95% <= 792.14 milliseconds
              98% <= 792.14 milliseconds
              99% <= 792.14 milliseconds
            99.9% <= 792.14 milliseconds

总结介绍

  1. Meter(速率统计器)

    • 目的:用于统计系统中某一事件的响应速率,如每秒请求数(TPS)或每秒查询数(QPS)。
    • 功能:该指标直接反映系统当前的处理能力。
    • 特点:主要关注的是事件的速率,衡量系统的处理能力。
  2. Gauge(计量器)

    • 目的:用于统计某个指标的瞬时值。
    • 功能:提供某一时刻的数值,而不是一个累积或平均值。
    • 特点:主要用于显示某个瞬时状态,如内存使用量、磁盘使用量等。
  3. Counter(计数器)

    • 本质:基于java.util.concurrent.atomic.LongAdder实现。
    • 功能:用于计数。
    • 特点:主要用于记录事件发生的次数。
  4. Histogram(直方图)

    • 目的:用于收集数据并生成直方图,用于分析数据的分布情况。
    • 功能:提供数据的分布情况,如响应时间的分布、请求大小的分布等。
    • 特点:除了提供平均值,还提供了数据的分布情况。
  5. Timer(计时器)

    • 描述:是Meter和Histogram的结合体。
    • 功能:用于统计接口请求速率和响应时长。
    • 特点:结合了速率统计和数据分布分析,提供了更全面的性能指标。

参考资料

转载自:https://juejin.cn/post/7330910316605505548
评论
请登录