Metrics —— JVM上的实时监控类库
Metrics提供了五個基本的度量類型:
Gauges(度量)
Counters(計數器)
Histograms(直方圖數據)
Meters(TPS計算器)
Timers(計時器)
Metrics中MetricRegistry是中心容器,它是程序中所有度量的容器,所有新的度量工具都要注冊到一個MetricRegistry實例中才可以使用,盡量在一個應用中保持讓這個MetricRegistry實例保持單例。
MetricRegistry 容器
在代碼中配置好這個MetricRegistry容器:
@Bean public?MetricRegistry?metrics()?{????return?new?MetricRegistry(); }Meters TPS計算器
TPS計算器這個名稱并不準確,Meters工具會幫助我們統計系統中某一個事件的速率。比如每秒請求數(TPS),每秒查詢數(QPS)等等。這個指標能反應系統當前的處理能力,幫助我們判斷資源是否已經不足。Meters本身是一個自增計數器。
通過MetricRegistry可以獲得一個Meter:
@Beanpublic?Meter?requestMeter(MetricRegistry?metrics)?{????return?metrics.meter("request"); }在請求中調用mark()方法,來增加計數,我們可以在不同的請求中添加不同的Meter,針對自己的系統完成定制的監控需求。
@RequestMapping("/hello")@ResponseBodypublic?String?helloWorld()?{requestMeter.mark();????return?"Hello?World"; }應用運行的過程中,在console中反饋的信息:
--?Meters?---------------------------------------------------------------------- request?????????????count?=?21055mean?rate?=?133.35?events/second1-minute?rate?=?121.66?events/second5-minute?rate?=?36.99?events/second15-minute?rate?=?13.33?events/second從以上信息中可以看出Meter可以為我們提供平均速率,以及采樣后的1分鐘,5分鐘,15分鐘的速率。
Histogram 直方圖數據
直方圖是一種非常常見的統計圖表,Metrics通過這個Histogram這個度量類型提供了一些方便實時繪制直方圖的數據。
和之前的Meter相同,我們可以通過MetricRegistry來獲得一個Histogram。
@Beanpublic?Histogram?responseSizes(MetricRegistry?metrics)?{????return?metrics.histogram("response-sizes"); }在應用中,需要統計的位置調用Histogram的update()方法。
responseSizes.update(new?Random().nextInt(10));比如我們需要統計某個方法的網絡流量,通過Histogram就非常的方便。
在console中Histogram反饋的信息:
--?Histograms?------------------------------------------------------------------ response-sizescount?=?21051min?=?0max?=?9mean?=?4.55stddev?=?2.88median?=?4.0075%?<=?7.0095%?<=?9.0098%?<=?9.0099%?<=?9.0099.9%?<=?9.00Histogram為我們提供了最大值,最小值和平均值等數據,利用這些數據,我們就可以開始繪制自定義的直方圖了。
Counter 計數器
Counter的本質就是一個AtomicLong實例,可以增加或者減少值,可以用它來統計隊列中Job的總數。
通過MetricRegistry也可以獲得一個Counter實例。
@Beanpublic?Counter?pendingJobs(MetricRegistry?metrics)?{????return?metrics.counter("requestCount"); }在需要統計數據的位置調用inc()和dec()方法。
//?增加計數pendingJobs.inc();//?減去計數pendingJobs.dec();console的輸出非常簡單:
--?Counters?--------------------------------------------------------------------requestCount?????????????count?=?21051只是輸出了當前度量的值。
Timer 計時器
Timer是一個Meter和Histogram的組合。這個度量單位可以比較方便地統計請求的速率和處理時間。對于接口中調用的延遲等信息的統計就比較方便了。如果發現一個方法的RPS(請求速率)很低,而且平均的處理時間很長,那么這個方法八成出問題了。
同樣,通過MetricRegistry獲取一個Timer的實例:
@Beanpublic?Timer?responses(MetricRegistry?metrics)?{????return?metrics.timer("executeTime"); }在需要統計信息的位置使用這樣的代碼:
final?Timer.Context?context?=?responses.time();try?{????//?handle?request}?finally?{context.stop(); }console中就會實時返回這個Timer的信息:
--?Timers?---------------------------------------------------------------------- executeTimecount?=?21061mean?rate?=?133.39?calls/second?????1-minute?rate?=?122.22?calls/second?????5-minute?rate?=?37.11?calls/second????15-minute?rate?=?13.37?calls/secondmin?=?0.00?millisecondsmax?=?0.01?millisecondsmean?=?0.00?millisecondsstddev?=?0.00?millisecondsmedian?=?0.00?milliseconds??????????????75%?<=?0.00?milliseconds??????????????95%?<=?0.00?milliseconds??????????????98%?<=?0.00?milliseconds??????????????99%?<=?0.00?milliseconds????????????99.9%?<=?0.01?millisecondsGauges 度量
除了Metrics提供的幾個度量類型,我們可以通過Gauges完成自定義的度量類型。比方說很簡單的,我們想看我們緩存里面的數據大小,就可以自己定義一個Gauges。
metrics.register(MetricRegistry.name(ListManager.class,?"cache",?"size"),????????????????(Gauge<Integer>)?()?->?cache.size());這樣Metrics就會一直監控Cache的大小。
除此之外有時候,我們需要計算自己定義的一直單位,比如消息隊列里面消費者(consumers)消費的速率和生產者(producers)的生產速率的比例,這也是一個度量。
public?class?CompareRatio?extends?RatioGauge?{????private?final?Meter?consumers;????private?final?Meter?producers;public?CacheHitRatio(Meter?consumers,?Meter?producers)?{????????this.consumers?=?consumers;????????this.producers?=?producers;}????@Overrideprotected?Ratio?getRatio()?{????????return?Ratio.of(consumers.getOneMinuteRate(),producers.getOneMinuteRate());} }把這個類也注冊到Metrics容器里面:
@Beanpublic?CompareRatio?cacheHitRatio(MetricRegistry?metrics,?Meter?requestMeter,?Meter?producers)?{CompareRatio?compareRatio?=?new?CompareRatio(consumers,?producers);metrics.register("生產者消費者比率",?compareRatio);????return?cacheHitRatio; }Reporter 報表
Metrics通過報表,將采集的數據展現到不同的位置,這里比如我們注冊一個ConsoleReporter到MetricRegistry中,那么console中就會打印出對應的信息。
@Beanpublic?ConsoleReporter?consoleReporter(MetricRegistry?metrics)?{????return?ConsoleReporter.forRegistry(metrics).convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build(); }除此之外Metrics還支持JMX、HTTP、Slf4j等等,可以訪問?http://metrics.dropwizard.io/3.1.0/manual/core/#reporters?來查看Metrics提供的報表,如果還是不能滿足自己的業務,也可以自己繼承Metrics提供的ScheduledReporter類完成自定義的報表類。
import java.lang.management.ManagementFactory;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.codahale.metrics.JmxReporter;
import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.Slf4jReporter;
import com.codahale.metrics.graphite.Graphite;
import com.codahale.metrics.graphite.GraphiteReporter;
import com.codahale.metrics.health.HealthCheckRegistry;
import com.codahale.metrics.jvm.BufferPoolMetricSet;
import com.codahale.metrics.jvm.FileDescriptorRatioGauge;
import com.codahale.metrics.jvm.GarbageCollectorMetricSet;
import com.codahale.metrics.jvm.MemoryUsageGaugeSet;
import com.codahale.metrics.jvm.ThreadStatesGaugeSet;
import com.ryantenney.metrics.spring.config.annotation.EnableMetrics;
import com.ryantenney.metrics.spring.config.annotation.MetricsConfigurerAdapter;
import com.zaxxer.hikari.HikariDataSource;
import fr.ippon.spark.metrics.SparkReporter;
@Configuration
@EnableMetrics(proxyTargetClass = true)
public class MetricsConfiguration extends MetricsConfigurerAdapter {
? ? private static final String PROP_METRIC_REG_JVM_MEMORY = "jvm.memory";
? ? private static final String PROP_METRIC_REG_JVM_GARBAGE = "jvm.garbage";
? ? private static final String PROP_METRIC_REG_JVM_THREADS = "jvm.threads";
? ? private static final String PROP_METRIC_REG_JVM_FILES = "jvm.files";
? ? private static final String PROP_METRIC_REG_JVM_BUFFERS = "jvm.buffers";
? ? private final Logger log = LoggerFactory.getLogger(MetricsConfiguration.class);
? ? private MetricRegistry metricRegistry = new MetricRegistry();
? ? private HealthCheckRegistry healthCheckRegistry = new HealthCheckRegistry();
? ? @Autowired
? ? private JHipsterProperties jHipsterProperties;
? ? @Autowired(required = false)
? ? private HikariDataSource hikariDataSource;
? ? @Override
? ? @Bean
? ? public MetricRegistry getMetricRegistry() {
? ? ? ? return metricRegistry;
? ? }
? ? @Override
? ? @Bean
? ? public HealthCheckRegistry getHealthCheckRegistry() {
? ? ? ? return healthCheckRegistry;
? ? }
? ? @PostConstruct
? ? public void init() {
? ? ? ? log.debug("Registering JVM gauges");
? ? ? ? metricRegistry.register(PROP_METRIC_REG_JVM_MEMORY, new MemoryUsageGaugeSet());
? ? ? ? metricRegistry.register(PROP_METRIC_REG_JVM_GARBAGE, new GarbageCollectorMetricSet());
? ? ? ? metricRegistry.register(PROP_METRIC_REG_JVM_THREADS, new ThreadStatesGaugeSet());
? ? ? ? metricRegistry.register(PROP_METRIC_REG_JVM_FILES, new FileDescriptorRatioGauge());
? ? ? ? metricRegistry.register(PROP_METRIC_REG_JVM_BUFFERS, new BufferPoolMetricSet(ManagementFactory.getPlatformMBeanServer()));
? ? ? ? if (hikariDataSource != null) {
? ? ? ? ? ? log.debug("Monitoring the datasource");
? ? ? ? ? ? hikariDataSource.setMetricRegistry(metricRegistry);
? ? ? ? }
? ? ? ? if (jHipsterProperties.getMetrics().getJmx().isEnabled()) {
? ? ? ? ? ? log.debug("Initializing Metrics JMX reporting");
? ? ? ? ? ? JmxReporter jmxReporter = JmxReporter.forRegistry(metricRegistry).build();
? ? ? ? ? ? jmxReporter.start();
? ? ? ? }
? ? ? ? if (jHipsterProperties.getMetrics().getLogs().isEnabled()) {
? ? ? ? ? ? log.info("Initializing Metrics Log reporting");
? ? ? ? ? ? final Slf4jReporter reporter = Slf4jReporter.forRegistry(metricRegistry)
? ? ? ? ? ? ? ? .outputTo(LoggerFactory.getLogger("metrics"))
? ? ? ? ? ? ? ? .convertRatesTo(TimeUnit.SECONDS)
? ? ? ? ? ? ? ? .convertDurationsTo(TimeUnit.MILLISECONDS)
? ? ? ? ? ? ? ? .build();
? ? ? ? ? ? reporter.start(jHipsterProperties.getMetrics().getLogs().getReportFrequency(), TimeUnit.SECONDS);
? ? ? ? }
? ? }
? ? @Configuration
? ? @ConditionalOnClass(Graphite.class)
? ? public static class GraphiteRegistry {
? ? ? ? private final Logger log = LoggerFactory.getLogger(GraphiteRegistry.class);
? ? ? ? @Autowired
? ? ? ? private MetricRegistry metricRegistry;
? ? ? ? @Autowired
? ? ? ? private JHipsterProperties jHipsterProperties;
? ? ? ? @PostConstruct
? ? ? ? private void init() {
? ? ? ? ? ? if (jHipsterProperties.getMetrics().getGraphite().isEnabled()) {
? ? ? ? ? ? ? ? log.info("Initializing Metrics Graphite reporting");
? ? ? ? ? ? ? ? String graphiteHost = jHipsterProperties.getMetrics().getGraphite().getHost();
? ? ? ? ? ? ? ? Integer graphitePort = jHipsterProperties.getMetrics().getGraphite().getPort();
? ? ? ? ? ? ? ? String graphitePrefix = jHipsterProperties.getMetrics().getGraphite().getPrefix();
? ? ? ? ? ? ? ? Graphite graphite = new Graphite(new InetSocketAddress(graphiteHost, graphitePort));
? ? ? ? ? ? ? ? GraphiteReporter graphiteReporter = GraphiteReporter.forRegistry(metricRegistry)
? ? ? ? ? ? ? ? ? ? .convertRatesTo(TimeUnit.SECONDS)
? ? ? ? ? ? ? ? ? ? .convertDurationsTo(TimeUnit.MILLISECONDS)
? ? ? ? ? ? ? ? ? ? .prefixedWith(graphitePrefix)
? ? ? ? ? ? ? ? ? ? .build(graphite);
? ? ? ? ? ? ? ? graphiteReporter.start(1, TimeUnit.MINUTES);
? ? ? ? ? ? }
? ? ? ? }
? ? }
? ? @Configuration
? ? @ConditionalOnClass(SparkReporter.class)
? ? public static class SparkRegistry {
? ? ? ? private final Logger log = LoggerFactory.getLogger(SparkRegistry.class);
? ? ? ? @Autowired
? ? ? ? private MetricRegistry metricRegistry;
? ? ? ? @Autowired
? ? ? ? private JHipsterProperties jHipsterProperties;
? ? ? ? @PostConstruct
? ? ? ? private void init() {
? ? ? ? ? ? if (jHipsterProperties.getMetrics().getSpark().isEnabled()) {
? ? ? ? ? ? ? ? log.info("Initializing Metrics Spark reporting");
? ? ? ? ? ? ? ? String sparkHost = jHipsterProperties.getMetrics().getSpark().getHost();
? ? ? ? ? ? ? ? Integer sparkPort = jHipsterProperties.getMetrics().getSpark().getPort();
? ? ? ? ? ? ? ? SparkReporter sparkReporter = SparkReporter.forRegistry(metricRegistry)
? ? ? ? ? ? ? ? ? ? .convertRatesTo(TimeUnit.SECONDS)
? ? ? ? ? ? ? ? ? ? .convertDurationsTo(TimeUnit.MILLISECONDS)
? ? ? ? ? ? ? ? ? ? .build(sparkHost, sparkPort);
? ? ? ? ? ? ? ? sparkReporter.start(1, TimeUnit.MINUTES);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
轉載于:https://blog.51cto.com/17099933344/1933119
總結
以上是生活随笔為你收集整理的Metrics —— JVM上的实时监控类库的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IE11 统治浏览器市场 Chrome
- 下一篇: HDU1163 Eddy's digit