系統(tǒng)監(jiān)控-Metric

Metrics is a Java library which gives you unparalleled insight into what your code does in production.
Metrics provides a powerful toolkit of ways to measure the behavior of critical components in your production environment.

簡單的說Metrics是一個監(jiān)控系統(tǒng)性能指標的一個Java庫。Cassandra使用它進行指標統(tǒng)計律罢。


在Maven的pom.xml中引入Metrics:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-core</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

Metrics使用非常簡單桩了,首先是Metrics的核心類

MetricRegistry類

The centerpiece of Metrics is the MetricRegistry class, which is the container for all your application’s metrics. Go ahead and create a new one:

我們一般直接new出Registry對象就可以完成Registry的創(chuàng)建风罩。

final MetricRegistry metrics = new MetricRegistry();

MetricRegistryclass中維護了一個Metric集合和一個MetricRegistryListener列表

    private final ConcurrentMap<String, Metric> metrics;
    private final List<MetricRegistryListener> listeners;
    /**
     * Creates a new {@link MetricRegistry}.
     */
    public MetricRegistry() {
        this.metrics = buildMap();
        this.listeners = new CopyOnWriteArrayList<MetricRegistryListener>();
    }

Metric的注冊、快速創(chuàng)建潘拱、獲取等等的基本功能东臀,都會維護Metric集合坯苹。

// 注冊
    public <T extends Metric> T register(String name, T metric) throws IllegalArgumentException {
        if (metric instanceof MetricSet) {
            registerAll(name, (MetricSet) metric);
        } else {
            final Metric existing = metrics.putIfAbsent(name, metric);
            if (existing == null) {
                onMetricAdded(name, metric);
            } else {
                throw new IllegalArgumentException("A metric named " + name + " already exists");
            }
        }
        return metric;
    }
// 創(chuàng)建+注冊 or 獲取
    public Meter meter(String name) {
        return getOrAdd(name, MetricBuilder.METERS);
    }
    public Timer timer(String name) {
        return getOrAdd(name, MetricBuilder.TIMERS);
    }
// 獲取
    public SortedMap<String, Gauge> getGauges() {
        return getGauges(MetricFilter.ALL);
    }
// etc

JmxReporterstrat的時候會向MetricRegistry注冊一個JmxListenerclass逢防,MetricRegistry會將它維護到MetricRegistryListener列表中叶沛。 JmxReporter會在后面介紹到,它是統(tǒng)計結(jié)果的輸出控制類胞四。MetricRegistry會在Metricadd or remove時將Metric傳遞給所有的JmxListener恬汁。JmxListenerMetric的真正使用者。
JmxReporter:

    private final JmxListener listener;

    private JmxReporter(MBeanServer mBeanServer,
                        String domain,
                        MetricRegistry registry,
                        MetricFilter filter,
                        MetricTimeUnits timeUnits, 
                        ObjectNameFactory objectNameFactory) {
        this.registry = registry;
        this.listener = new JmxListener(mBeanServer, domain, filter, timeUnits, objectNameFactory);
    }
    public void start() {
        registry.addListener(listener);
    }

MetricRegistry:

    private void onMetricAdded(String name, Metric metric) {
        for (MetricRegistryListener listener : listeners) {
            notifyListenerOfAddedMetric(listener, metric, name);
        }
    }

Reporter接口

它是Metrics輸出控制類的統(tǒng)一接口辜伟,它將采集的數(shù)據(jù)展現(xiàn)到不同的位置氓侧。Metrics提供兩個實現(xiàn)類JmxReporterScheduledReporter
JmxReporter會通過JMX報告指標导狡,它需要依賴metrics-jmx包

<dependency>
    <groupId>io.dropwizard.metrics</groupId>
    <artifactId>metrics-jmx</artifactId>
    <version>${metrics.version}</version>
</dependency>
final JmxReporter reporter = JmxReporter.forRegistry(registry).build();
reporter.start();

ScheduledReporter顧名思義约巷,會定時的輸出報表。ConsoleReporter旱捧、Slf4jReporter等等Metric自帶的所以Reporter都是繼承于它独郎,一般我們自定義的Reporter也會繼承它。

A Console Reporter is exactly what it sounds like - report to the console. This reporter will print every second.

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

Metrics

最后來看下Metrics提供了五個基本的Metrics :

  1. Meters(TPS)

A meter measures the rate of events over time (e.g., “requests per second”). In addition to the mean rate, meters also track 1-, 5-, and 15-minute moving averages.

使用起來非常簡單枚赡,這里暫不多介紹氓癌,只從官網(wǎng)復制了些實例代碼展示下如何使用:

private final MetricRegistry metrics = new MetricRegistry();
private final Meter requests = metrics.meter("requests");

public void handleRequest(Request request, Response response) {
    requests.mark();
    // etc
}

結(jié)果:

19-6-11 10:09:32 ===============================================================

-- Meters ----------------------------------------------------------------------
meter
             count = 56
         mean rate = 1.00 events/second
     1-minute rate = 1.00 events/second
     5-minute rate = 1.00 events/second
    15-minute rate = 1.00 events/second

還有一些常用方法:

    @Override
    public long getCount() {
        return count.sum();
    }
    @Override
    public double getOneMinuteRate() {
        tickIfNecessary();
        return m1Rate.getRate(TimeUnit.SECONDS);
    }
// etc
  1. Gauges
    如果說上面Meters是一個動態(tài)的統(tǒng)計的話,Gauges就是一個靜態(tài)的統(tǒng)計贫橙。它能統(tǒng)計出關(guān)注對象當時的狀態(tài)贪婉。

A gauge is an instantaneous measurement of a value. For example, we may want to measure the number of pending jobs in a queue:

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();
                             }
                         });
    }
}
MetricRegistry.name(QueueManager.class, "jobs", "size");

它的效率受時間復雜度影響

For most queue and queue-like structures, you won’t want to simply return queue.size(). Most of java.util and java.util.concurrent have implementations of #size() which are O(n), which means your gauge will be slow (potentially while holding a lock).

  1. Counters
    類似于一個AtomicLong
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();
}

官方推薦使用#counter(String)代替#register(String, Metric)創(chuàng)建卢肃。

As you can see, the API for counters is slightly different: #counter(String) instead of #register(String, Metric). While you can use register and create your own Counter instance, #counter(String) does all the work for you, and allows you to reuse metrics with the same name.
Also, we’ve statically imported MetricRegistry’s name method in this scope to reduce clutter.

  1. Histograms(直方圖)
    直方圖是一種用于統(tǒng)計數(shù)據(jù)的圖表疲迂,Histogram能統(tǒng)計數(shù)據(jù)的最小值、最大值莫湘、平均值等尤蒿,還有測量中位數(shù)、75位幅垮、90位腰池、95位、98位军洼、99位和99.9巩螃。

A histogram measures the statistical distribution of values in a stream of data. In addition to minimum, maximum, mean, etc., it also measures median, 75th, 90th, 95th, 98th, 99th, and 99.9th percentiles.

private final Histogram responseSizes = metrics.histogram(name(RequestHandler.class, "response-sizes"));

public void handleRequest(Request request, Response response) {
    // etc
    responseSizes.update(response.getContent().length);
}

有一點在官網(wǎng)上特別提醒:歷史數(shù)據(jù)的大小之間影響到了Histogram的響應(yīng)速度,所以Histogram都需要設(shè)定了默認大小匕争。

This histogram will measure the size of responses in bytes.

Histogram基本功能都是通過內(nèi)部的Reservoir來實現(xiàn)的避乏。使用#histogram(String)來創(chuàng)建會默認使用ExponentiallyDecayingReservoir,并且他的默認大小是1028甘桑。

        MetricBuilder<Histogram> HISTOGRAMS = new MetricBuilder<Histogram>() {
            @Override
            public Histogram newMetric() {
                return new Histogram(new ExponentiallyDecayingReservoir());
            }

            @Override
            public boolean isInstance(Metric metric) {
                return Histogram.class.isInstance(metric);
            }
        };
  1. Timers
    TimerMeter類似拍皮,但它的功能比Meter強大很多歹叮。Meter只統(tǒng)計次數(shù),Timer會統(tǒng)計過程的耗時铆帽,并提供更豐富的輸出統(tǒng)計咆耿。
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();
    }
}

在使用上,我們需在計時開始處創(chuàng)建Context爹橱,出口處調(diào)用#context.stop()萨螺。
簡單看下源碼,我們能發(fā)現(xiàn)Timer內(nèi)部其實就是使用 MeterHistogram來實現(xiàn)的愧驱。

    /**
     * Creates a new {@link Timer} that uses the given {@link Reservoir} and {@link Clock}.
     *
     * @param reservoir the {@link Reservoir} implementation the timer should use
     * @param clock  the {@link Clock} implementation the timer should use
     */
    public Timer(Reservoir reservoir, Clock clock) {
        this.meter = new Meter(clock);
        this.clock = clock;
        this.histogram = new Histogram(reservoir);
    }

    private void update(long duration) {
        if (duration >= 0) {
            histogram.update(duration);
            meter.mark();
        }
    }

Health Checks

Metrics還提供了服務(wù)的集中健康檢查慰技。
這需要在Maven的pom.xml中引入新的Metrics包:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-healthchecks</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

基本使用流程:

  1. 創(chuàng)建各種健康檢查的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());
        }
    }
}
  1. HealthCheck注冊到HealthCheckRegistry
final HealthCheckRegistry healthChecks = new HealthCheckRegistry();

healthChecks.register("postgres", new DatabaseHealthCheck(database));
  1. 運行HealthCheckRegistry:#runHealthChecks()
final Map<String, HealthCheck.Result> results = healthChecks.runHealthChecks();
  1. 通過遍歷返回值判斷健康狀態(tài)起意。
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();
        }
    }
}

JVM Instrumentation

這是Metrics中對于jvm的監(jiān)控。

The metrics-jvm module contains a number of reusable gauges and metric sets which allow you to easily instrument JVM internals.

它需要引入對于Jar包:

<dependencies>
    <dependency>
        <groupId>io.dropwizard.metrics</groupId>
        <artifactId>metrics-jvm</artifactId>
        <version>${metrics.version}</version>
    </dependency>
</dependencies>

Metrics提供了各種jvm的指標metricMetricSet子類邑雅,在子類對ManagementFactory各種獲取屬性進行了分裝,來實現(xiàn)對jvm的監(jiān)控。

    /**
     * Creates a new set of gauges using the default MXBeans.
     * Caches the information for the given interval and time unit.
     *
     * @param interval cache interval
     * @param unit     cache interval time unit
     */
    public CachedThreadStatesGaugeSet(long interval, TimeUnit unit) {
        this(ManagementFactory.getThreadMXBean(), new ThreadDeadlockDetector(), interval, unit);
    }

    public ClassLoadingGaugeSet() {
        this(ManagementFactory.getClassLoadingMXBean());
    }

    /**
     * Creates a new gauge using the platform OS bean.
     */
    public FileDescriptorRatioGauge() {
        this(ManagementFactory.getOperatingSystemMXBean());
    }

// etc

它支持的指標包括:

  • 運行所有支持的垃圾收集器的計數(shù)和已用時間
  • 所有內(nèi)存池的內(nèi)存使用情況,包括堆外內(nèi)存
  • 線程狀態(tài)的細分柒爸,包括死鎖
  • 文件描述符用法
  • 緩沖池大小和利用率
    BufferPoolMetricSet:JVM的直接緩沖池和映射緩沖池的數(shù)量統(tǒng)計。
    ThreadStatesGaugeSet:檢測處于不同狀態(tài)的線程數(shù)和死鎖檢測的Gauge事扭。
    CachedThreadStatesGaugeSet:同上揍鸟,多創(chuàng)建了一個CachedGauge
    ClassLoadingGaugeSet:JVM類加載器的Gauge句旱。
    FileDescriptorRatioGauge:是對于操作系統(tǒng)FileDescriptor的一個統(tǒng)計,可以用來監(jiān)控IO流的釋放等等晰奖。
    GarbageCollectorMetricSet:可以統(tǒng)計GC的次數(shù)和使用時間谈撒。
    JmxAttributeGauge:主要統(tǒng)計JVM的runtime,還在Gauge獲取了JVM的名稱匾南、供應(yīng)商信息啃匿。
    MemoryUsageGaugeSet:對于內(nèi)存的監(jiān)控(包含堆內(nèi)內(nèi)存和堆外內(nèi)存)。


Metric官方Document

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蛆楞,一起剝皮案震驚了整個濱河市溯乒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌豹爹,老刑警劉巖裆悄,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異臂聋,居然都是意外死亡光稼,警方通過查閱死者的電腦和手機或南,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來艾君,“玉大人采够,你說我怎么就攤上這事”ⅲ” “怎么了蹬癌?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長虹茶。 經(jīng)常有香客問我逝薪,道長,這世上最難降的妖魔是什么写烤? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任翼闽,我火速辦了婚禮,結(jié)果婚禮上洲炊,老公的妹妹穿的比我還像新娘感局。我一直安慰自己,他們只是感情好暂衡,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布询微。 她就那樣靜靜地躺著,像睡著了一般狂巢。 火紅的嫁衣襯著肌膚如雪撑毛。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天唧领,我揣著相機與錄音藻雌,去河邊找鬼。 笑死斩个,一個胖子當著我的面吹牛胯杭,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播受啥,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼做个,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滚局?” 一聲冷哼從身側(cè)響起居暖,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎藤肢,沒想到半個月后太闺,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡嘁圈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年跟束,在試婚紗的時候發(fā)現(xiàn)自己被綠了莺奸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡冀宴,死狀恐怖灭贷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情略贮,我是刑警寧澤甚疟,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站逃延,受9級特大地震影響览妖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜揽祥,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一讽膏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拄丰,春花似錦府树、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至载矿,卻和暖如春垄潮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闷盔。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工弯洗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人逢勾。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓涂召,卻偏偏與公主長得像,于是被迫代替她去往敵國和親敏沉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容