Metrics —— JVM上的实时监控类库
Metrics提供了五個(gè)基本的度量類型:
Gauges(度量)
Counters(計(jì)數(shù)器)
Histograms(直方圖數(shù)據(jù))
Meters(TPS計(jì)算器)
Timers(計(jì)時(shí)器)
Metrics中MetricRegistry是中心容器,它是程序中所有度量的容器,所有新的度量工具都要注冊到一個(gè)MetricRegistry實(shí)例中才可以使用,盡量在一個(gè)應(yīng)用中保持讓這個(gè)MetricRegistry實(shí)例保持單例。
MetricRegistry 容器
在代碼中配置好這個(gè)MetricRegistry容器:
@Bean public?MetricRegistry?metrics()?{????return?new?MetricRegistry(); }Meters TPS計(jì)算器
TPS計(jì)算器這個(gè)名稱并不準(zhǔn)確,Meters工具會幫助我們統(tǒng)計(jì)系統(tǒng)中某一個(gè)事件的速率。比如每秒請求數(shù)(TPS),每秒查詢數(shù)(QPS)等等。這個(gè)指標(biāo)能反應(yīng)系統(tǒng)當(dāng)前的處理能力,幫助我們判斷資源是否已經(jīng)不足。Meters本身是一個(gè)自增計(jì)數(shù)器。
通過MetricRegistry可以獲得一個(gè)Meter:
@Beanpublic?Meter?requestMeter(MetricRegistry?metrics)?{????return?metrics.meter("request"); }在請求中調(diào)用mark()方法,來增加計(jì)數(shù),我們可以在不同的請求中添加不同的Meter,針對自己的系統(tǒng)完成定制的監(jiān)控需求。
@RequestMapping("/hello")@ResponseBodypublic?String?helloWorld()?{requestMeter.mark();????return?"Hello?World"; }應(yīng)用運(yùn)行的過程中,在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 直方圖數(shù)據(jù)
直方圖是一種非常常見的統(tǒng)計(jì)圖表,Metrics通過這個(gè)Histogram這個(gè)度量類型提供了一些方便實(shí)時(shí)繪制直方圖的數(shù)據(jù)。
和之前的Meter相同,我們可以通過MetricRegistry來獲得一個(gè)Histogram。
@Beanpublic?Histogram?responseSizes(MetricRegistry?metrics)?{????return?metrics.histogram("response-sizes"); }在應(yīng)用中,需要統(tǒng)計(jì)的位置調(diào)用Histogram的update()方法。
responseSizes.update(new?Random().nextInt(10));比如我們需要統(tǒng)計(jì)某個(gè)方法的網(wǎng)絡(luò)流量,通過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為我們提供了最大值,最小值和平均值等數(shù)據(jù),利用這些數(shù)據(jù),我們就可以開始繪制自定義的直方圖了。
Counter 計(jì)數(shù)器
Counter的本質(zhì)就是一個(gè)AtomicLong實(shí)例,可以增加或者減少值,可以用它來統(tǒng)計(jì)隊(duì)列中Job的總數(shù)。
通過MetricRegistry也可以獲得一個(gè)Counter實(shí)例。
@Beanpublic?Counter?pendingJobs(MetricRegistry?metrics)?{????return?metrics.counter("requestCount"); }在需要統(tǒng)計(jì)數(shù)據(jù)的位置調(diào)用inc()和dec()方法。
//?增加計(jì)數(shù)pendingJobs.inc();//?減去計(jì)數(shù)pendingJobs.dec();console的輸出非常簡單:
--?Counters?--------------------------------------------------------------------requestCount?????????????count?=?21051只是輸出了當(dāng)前度量的值。
Timer 計(jì)時(shí)器
Timer是一個(gè)Meter和Histogram的組合。這個(gè)度量單位可以比較方便地統(tǒng)計(jì)請求的速率和處理時(shí)間。對于接口中調(diào)用的延遲等信息的統(tǒng)計(jì)就比較方便了。如果發(fā)現(xiàn)一個(gè)方法的RPS(請求速率)很低,而且平均的處理時(shí)間很長,那么這個(gè)方法八成出問題了。
同樣,通過MetricRegistry獲取一個(gè)Timer的實(shí)例:
@Beanpublic?Timer?responses(MetricRegistry?metrics)?{????return?metrics.timer("executeTime"); }在需要統(tǒng)計(jì)信息的位置使用這樣的代碼:
final?Timer.Context?context?=?responses.time();try?{????//?handle?request}?finally?{context.stop(); }console中就會實(shí)時(shí)返回這個(gè)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提供的幾個(gè)度量類型,我們可以通過Gauges完成自定義的度量類型。比方說很簡單的,我們想看我們緩存里面的數(shù)據(jù)大小,就可以自己定義一個(gè)Gauges。
metrics.register(MetricRegistry.name(ListManager.class,?"cache",?"size"),????????????????(Gauge<Integer>)?()?->?cache.size());這樣Metrics就會一直監(jiān)控Cache的大小。
除此之外有時(shí)候,我們需要計(jì)算自己定義的一直單位,比如消息隊(duì)列里面消費(fèi)者(consumers)消費(fèi)的速率和生產(chǎn)者(producers)的生產(chǎn)速率的比例,這也是一個(gè)度量。
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());} }把這個(gè)類也注冊到Metrics容器里面:
@Beanpublic?CompareRatio?cacheHitRatio(MetricRegistry?metrics,?Meter?requestMeter,?Meter?producers)?{CompareRatio?compareRatio?=?new?CompareRatio(consumers,?producers);metrics.register("生產(chǎn)者消費(fèi)者比率",?compareRatio);????return?cacheHitRatio; }Reporter 報(bào)表
Metrics通過報(bào)表,將采集的數(shù)據(jù)展現(xiàn)到不同的位置,這里比如我們注冊一個(gè)ConsoleReporter到MetricRegistry中,那么console中就會打印出對應(yīng)的信息。
@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提供的報(bào)表,如果還是不能滿足自己的業(yè)務(wù),也可以自己繼承Metrics提供的ScheduledReporter類完成自定義的報(bào)表類。
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);
? ? ? ? ? ? }
? ? ? ? }
? ? }
}
轉(zhuǎn)載于:https://blog.51cto.com/17099933344/1933119
總結(jié)
以上是生活随笔為你收集整理的Metrics —— JVM上的实时监控类库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: IE11 统治浏览器市场 Chrome
- 下一篇: HDU1163 Eddy's digit