首頁 > 軟體

詳解Metrics應用監控指標的使用說明

2022-02-22 13:02:04

題前:做過虛擬化級別、系統級別、容器級別監控;應用級別監控有哪些方法可以做?

Metrics是個很好的選擇。java、python、go均可支援。

Metrics可以為你的程式碼的執行提供無與倫比的洞察力。作為一款監控指標的度量類庫,它提供了很多模組可以為第三方庫或者應用提供輔助統計資訊, 比如Jetty, Logback, Log4j, Apache HttpClient, Ehcache, JDBI, Jersey, 它還可以將度量資料傳送給Ganglia和Graphite以提供圖形化的監控。

Metrics提供了Gauge、Counter、Meter、Histogram、Timer等度量工具類以及Health Check功能。

參照Metric庫

將metrics-core加入到maven pom.xml中:

<dependencies> 
    <dependency> 
        <groupId>com.codahale.metrics</groupId> 
        <artifactId>metrics-core</artifactId> 
        <version>${metrics.version}</version> 
    </dependency> 
</dependencies>

metrics.version 設定為metrics最新的版本。
現在你可以在你的程式程式碼中加入一些度量了。

Registry

Metric的中心部件是MetricRegistry。 它是程式中所有度量metric的容器。讓我們接著在程式碼中加入一行:

final MetricRegistry metrics = new MetricRegistry();

Gauge (儀表)

Gauge代表一個度量的即時值。 當你開汽車的時候, 當前速度是Gauge值。 你測體溫的時候, 體溫計的刻度是一個Gauge值。 當你的程式執行的時候, 記憶體使用量和CPU佔用率都可以通過Gauge值來度量。
比如我們可以檢視一個佇列當前的size。

public class QueueManager { 
    private final Queue queue; 
    public QueueManager(MetricRegistry metrics, String name) { 
        this.queue = new Queue();
        metrics.register(MetricRegistry.name(QueueManager.class, name, "size"), 
            new Gauge<Integer>() { 
                @Override 
                public Integer getValue() { 
                    return queue.size(); 
                } 
            }
        ); 
    } 
}

registry 中每一個metric都有唯一的名字。 它可以是以.連線的字串。 如"things.count" 和 "com.colobu.Thing.latency"。 MetricRegistry 提供了一個靜態的輔助方法用來生成這個名字:

MetricRegistry.name(QueueManager.class, "jobs", "size")

生成的name為com.colobu.QueueManager.jobs.size

實際程式設計中對於佇列或者類似佇列的資料結構,你不會簡單的度量queue.size(), 因為在java.util和java.util.concurrent包中大部分的queue的#size是O(n),這意味的呼叫此方法會有效能的問題, 更深一步,可能會有lock的問題。

RatioGauge可以計算兩個Gauge的比值。 Meter和Timer可以參考下面的程式碼建立。下面的程式碼用來計算計算命中率 (hit/call)。

public class CacheHitRatio extends RatioGauge { 
    private final Meter hits; 
    private final Timer calls; 
    public CacheHitRatio(Meter hits, Timer calls) { 
        this.hits = hits; this.calls = calls; 
    } 
    @Override 
    public Ratio getValue() { 
        return Ratio.of(hits.oneMinuteRate(), calls.oneMinuteRate()); 
    } 
}

CachedGauge可以快取耗時的測量。DerivativeGauge可以參照另外一個Gauage。

Counter (計數器)

Counter是一個AtomicLong範例, 可以增加或者減少值。 例如,可以用它來計數佇列中加入的Job的總數。

private final Counter pendingJobs 
    = metrics.counter(name(QueueManager.class, "pending-jobs"));
public void addJob(Job job) { 
    pendingJobs.inc(); 
    queue.offer(job); 
} 
public Job takeJob() { 
    pendingJobs.dec(); 
    return queue.take(); 
}

和上面Gauage不同,這裡我們使用的是metrics.counter方法而不是metrics.register方法。 使用metrics.counter更簡單。

Meter ()

Meter用來計算事件的速率。 例如 request per second。 還可以提供1分鐘,5分鐘,15分鐘不斷更新的平均速率。

private final Histogram responseSizes 
    = metrics.histogram(name(RequestHandler.class, "response-sizes"); 
public void handleRequest(Request request, Response response) { 
    // etc 
    responseSizes.update(response.getContent().length); 
}

Histogram (直方圖)

Histogram可以為資料流提供統計資料。 除了最大值,最小值,平均值外,它還可以測量 中值(median),百分比比如XX%這樣的Quantile資料 。

private final Histogram responseSizes     = metrics.histogram(name(RequestHandler.class, "response-sizes"); public void handleRequest(Request request, Response response) {     // etc     responseSizes.update(response.getContent().length); }

這個例子用來統計response的位元組數。
Metrics提供了一批的Reservoir實現,非常有用。例如SlidingTimeWindowReservoir 用來統計最新N個秒(或其它時間單元)的資料。

Timer (計時器)

Timer用來測量一段程式碼被呼叫的速率和用時。

private final Timer responses = metrics.timer(name(RequestHandler.class, "responses")); 
public String handleRequest(Request request, Response response) { 
    final Timer.Context context = responses.time(); 
    try { 
        // etc; 
        return "OK"; 
    } finally { 
        context.stop(); 
    } 
}

這段程式碼用來計算中間的程式碼用時以及request的速率。

Health Check (健康檢查)

Metric還提供了服務健康檢查能力, 由metrics-healthchecks模組提供。
先建立一個HealthCheckRegistry範例。

final HealthCheckRegistry healthChecks = new HealthCheckRegistry();

再實現一個HealthCheck子類, 用來檢查資料庫的狀態。

public class DatabaseHealthCheck extends HealthCheck { 
    private final Database database; 
    public DatabaseHealthCheck(Database database) { 
        this.database = database; 
    } 
    @Override 
    public HealthCheck.Result check() throws Exception { 
        if (database.isConnected()) { 
            return HealthCheck.Result.healthy(); 
        } else { 
            return HealthCheck.Result.unhealthy("Cannot connect to " +    
                database.getUrl()); 
        } 
    } 
}

註冊一下。

healthChecks.register("mysql", new DatabaseHealthCheck(database));

最後執行健康檢查並檢視檢查結果。

final Map<String, HealthCheck.Result> results = healthChecks.runHealthChecks(); 
for (Entry<String, HealthCheck.Result> entry : results.entrySet()) { 
    if (entry.getValue().isHealthy()) { 
        System.out.println(entry.getKey() + " is healthy"); 
    } else { 
        System.err.println(entry.getKey() + " is UNHEALTHY: " +     
            entry.getValue().getMessage()); 
        final Throwable e = entry.getValue().getError(); 
        if (e != null) { 
            e.printStackTrace(); 
        } 
    } 
}

Metric內建一個ThreadDeadlockHealthCheck, 它使用java內建的執行緒死鎖檢查方法來檢查程式中是否有死鎖。

JMX報表

通過JMX報告Metric。

final JmxReporter reporter = JmxReporter.forRegistry(registry).build(); 
reporter.start();

一旦啟動, 所有registry中註冊的metric都可以通過JConsole或者VisualVM檢視 (通過MBean外掛)。

HTTP報表

Metric也提供了一個servlet (AdminServlet)提供JSON風格的報表。它還提供了單一功能的servlet (MetricsServlet, HealthCheckServlet, ThreadDumpServlet, PingServlet)。
你需要在pom.xml加入metrics-servlets。

<dependency> 
    <groupId>com.codahale.metrics</groupId> 
    <artifactId>metrics-servlets</artifactId> 
    <version>${metrics.version}</version> 
</dependency>

其它報表

除了JMX和HTTP, metric還提供其它報表。

STDOUT, using ConsoleReporter from metrics-core

final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry) 
                                    .convertRatesTo(TimeUnit.SECONDS) 
                                    .convertDurationsTo(TimeUnit.MILLISECONDS) 
                                    .build(); 
 
reporter.start(1, TimeUnit.MINUTES);

CSV files, using CsvReporter from metrics-core

final CsvReporter reporter = CsvReporter.forRegistry(registry) 
                                .formatFor(Locale.US) 
                                .convertRatesTo(TimeUnit.SECONDS) 
                                .convertDurationsTo(TimeUnit.MILLISECONDS) 
                                .build(new File("~/projects/data/")); 
reporter.start(1, TimeUnit.SECONDS);

SLF4J loggers, using Slf4jReporter from metrics-core

final Slf4jReporter reporter = Slf4jReporter.forRegistry(registry)             
                               .outputTo(LoggerFactory.getLogger("com.example.metrics"))     
                                .convertRatesTo(TimeUnit.SECONDS) 
                                .convertDurationsTo(TimeUnit.MILLISECONDS) 
                                .build(); 
reporter.start(1, TimeUnit.MINUTES);

Ganglia, using GangliaReporter from metrics-ganglia

final GMetric ganglia = new GMetric("ganglia.example.com", 8649, UDPAddressingMode.MULTICAST, 1); 
final GangliaReporter reporter = GangliaReporter.forRegistry(registry)         
                                    .convertRatesTo(TimeUnit.SECONDS) 
                                    .convertDurationsTo(TimeUnit.MILLISECONDS) 
                                    .build(ganglia); 
reporter.start(1, TimeUnit.MINUTES);

Graphite, using GraphiteReporter from metrics-graphite

MetricSet

可以將一組Metric組織成一組便於重用。

final Graphite graphite = new Graphite(new InetSocketAddress("graphite.example.com", 2003)); 
final GraphiteReporter reporter = GraphiteReporter.forRegistry(registry) 
                                    .prefixedWith("web1.example.com") 
                                    .convertRatesTo(TimeUnit.SECONDS)         
                                    .convertDurationsTo(TimeUnit.MILLISECONDS) 
                                    .filter(MetricFilter.ALL) 
                                    .build(graphite); 
reporter.start(1, TimeUnit.MINUTES);

一些模組 metrics-json提供了json格式的序列化。
以及為其它庫提供度量的能力metrics-ehcachemetrics-httpclientmetrics-jdbimetrics-jerseymetrics-jettymetrics-log4jmetrics-logbackmetrics-jvmmetrics-servlet 注意不是metrics-servlets

第三方庫

這裡重點介紹一下Metrics for Spring

Metrics for Spring

這個庫為Spring增加了Metric庫, 提供基於XML或者註解方式。

  • 可以使用註解建立metric和代理類。 @Timed, @Metered, @ExceptionMetered, @Counted
  • 為註解了 @Gauge 和 @CachedGauge的bean註冊Gauge
  • 為@Metric註解的欄位自動裝配
  • 註冊HealthCheck
  • 通過XML設定產生報表
  • 通過XML註冊metric和metric組

你需要在pom.xml加入

<dependency> 
    <groupId>com.ryantenney.metrics</groupId> 
    <artifactId>metrics-spring</artifactId> 
    <version>3.0.1</version> 
</dependency>

基本用法

XML風格的設定

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:metrics="http://www.ryantenney.com/schema/metrics" 
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans         
        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd             
        http://www.ryantenney.com/schema/metrics http://www.ryantenney.com/schema/metrics/metrics-3.0.xsd"> 
    <!-- Registry should be defined in only one context XML file --> 
    <metrics:metric-registry id="metrics" /> 
    <!-- annotation-driven must be included in all context files --> 
    <metrics:annotation-driven metric-registry="metrics" /> 
    <!-- (Optional) Registry should be defined in only one context XML file -->
    <metrics:reporter type="console" metric-registry="metrics" period="1m" /> 
    <!-- (Optional) The metrics in this example require the metrics-jvm jar-->
    <metrics:register metric-registry="metrics"> 
        <bean metrics:name="jvm.gc" class="com.codahale.metrics.jvm.GarbageCollectorMetricSet" />
        <bean metrics:name="jvm.memory" class="com.codahale.metrics.jvm.MemoryUsageGaugeSet" /> 
        <bean metrics:name="jvm.thread-states" class="com.codahale.metrics.jvm.ThreadStatesGaugeSet" /> 
        <bean metrics:name="jvm.fd.usage" class="com.codahale.metrics.jvm.FileDescriptorRatioGauge" /> 
    </metrics:register> 
    <!-- Beans and other Spring config --> 
</beans>

java註解的方式

import java.util.concurrent.TimeUnit; 
import org.springframework.context.annotation.Configuration; 
import com.codahale.metrics.ConsoleReporter; 
import com.codahale.metrics.MetricRegistry; 
import com.codahale.metrics.SharedMetricRegistries; 
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics; 
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter; 
 
@Configuration 
@EnableMetrics 
public class SpringConfiguringClass extends MetricsConfigurerAdapter { 
    @Override 
    public void configureReporters(MetricRegistry metricRegistry) { 
    ConsoleReporter.forRegistry(metricRegistry).build().start(1, TimeUnit.MINUTES); 
    } 
}

注: go Metrics使用: Go語言metrics應用監控指標基本使用說明

以上就是詳解Metrics應用監控指標的使用說明的詳細內容,更多關於Metrics應用監控指標使用的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com