1. 程式人生 > >利用AppMetrics對Web進行監控教程

利用AppMetrics對Web進行監控教程

利用AppMetrics對Web進行監控教程

一、基礎準備

1. 安裝依賴

這裡可以通過nuget或使用命令列進行安裝,具體需要安裝的類庫如下(注意版本):

Install-Package App.Metrics.AspNetCore.Mvc -Version 2.0.0

由於我們需要相容Prometheus進行監控,所以我們還需要安裝對應的格式化庫,具體如下:

Install-Package App.Metrics.Formatters.Prometheus -Version 2.0.0

以上就是需要的類庫,接下來我們開始進行其他初始化部分。

2. 初始配置

為了保證其能夠正常工作,我們需要根據不同的環境設定對應的appsettings.json

檔案從而讓度量指標可以根據不同的環境進行輸出,這裡考慮到實際情況尚未存在不同的配置可能性故統一配置即可,開啟appsettings.json輸入下配置項:

{
  "MetricsOptions": {
    "DefaultContextLabel": "MetricsApplication",
    "Enabled": true
  },
  "MetricsWebTrackingOptions": {
    "ApdexTrackingEnabled": true,
    "ApdexTSeconds": 0.3,
    "IgnoredHttpStatusCodes": [ 404 ],
    "IgnoreRoutesRegexPatterns": [],
    "OAuth2TrackingEnabled": false
  },
  "MetricEndpointsOptions": {
    "MetricsEndpointEnabled": true,
    "MetricsTextEndpointEnabled": true,
    "EnvironmentInfoEndpointEnabled": true
  }
}

引數DefaultContextLabel可以設定為我們期望其他名稱,這裡建議採用專案的簡寫名稱,保證專案之間不存在衝突即可。引數ApdexTSeconds用於設定應用的響應能力標準,其採用了當前流行的Apdex標準,這裡使用者可以根據自身應用的實際情況調整對應的引數,其他相關引數建議預設即可。

3. 啟用度量指標

因為我們的資料需要符合Promethues格式,所以後續教程我們會替換預設的格式採用符合的格式。首先我們需要Program.cs裡輸入以下內容:

        public static IWebHost BuildWebHost(string[] args)
        {
            Metrics = AppMetrics.CreateDefaultBuilder()
                .OutputMetrics.AsPrometheusPlainText()
                .OutputMetrics.AsPrometheusProtobuf()
                .Build();

            return WebHost.CreateDefaultBuilder(args)
                    .ConfigureMetrics(Metrics)
                    .UseMetrics(options =>
                    {
                        options.EndpointOptions = endpointsOptions =>
                        {
                            endpointsOptions.MetricsTextEndpointOutputFormatter = Metrics.OutputMetricsFormatters.OfType<MetricsPrometheusTextOutputFormatter>().First();
                            endpointsOptions.MetricsEndpointOutputFormatter = Metrics.OutputMetricsFormatters.OfType<MetricsPrometheusProtobufOutputFormatter>().First();
                        };
                    })
                    .UseStartup<Startup>()
                    .Build();
        }

其中為了能夠支援其他格式,我們需要手動例項化Metrics物件完成相關初始化然後將其注入到asp.net core中,其中相關格式的程式碼主要是由以下這幾部分組成:

OutputMetrics.AsPrometheusPlainText()
OutputMetrics.AsPrometheusProtobuf()

endpointsOptions.MetricsTextEndpointOutputFormatter = Metrics.OutputMetricsFormatters.OfType<MetricsPrometheusTextOutputFormatter>().First();
endpointsOptions.MetricsEndpointOutputFormatter = Metrics.OutputMetricsFormatters.OfType<MetricsPrometheusProtobufOutputFormatter>().First();

完成以上操作後,我們最後還需要進行其他配置,開啟Startup.cs檔案增加如下內容:

services.AddMvc().AddMetrics();

至此我們就完成了基本的初始化了,通過啟動程式並訪問localhost:5000/metrics-text即可檢視最終的輸出內容。

二、自定義指標

由於其內部已經預設提供了若干的指標,但是並不能符合實際業務的需求故以下將對常用的度量指標型別以及用法進行介紹,這裡這裡大家通過注入IMetrics介面物件即可訪問,所以下面這部分程式碼不在闡述。

1. 儀表盤(Gauge)

最常見的型別,主要是用於直接反應當前的指標情況,比如我們常見的CPU和記憶體基本都是使用這種方式進行顯示的,可以直觀的看到當前的實際的狀態情況。對於所有的指標我們都需要定義對應的Options,當然這可以完成攜程靜態變數供應用程式全域性使用。

比如下面我們定義一個表示當前發生錯誤次數的指標:

GaugeOptions Errors = new GaugeOptions()
{
    Name = "Errors"
};

完成指標的定義後,我們就可以在需要使用的地方進行指標資料的修改,比如下面我們將錯誤數量設定為10:

metrics.Measure.Gauge.SetValue(MyMetricsRegistry.Errors, 10);

這樣我們就完成了指標的設定,但是有時候我們還想卻分具體的Error是那個層面發起的,這個時候我們需要使用到Tag了,下面我們在設定值的同時設定指標,當然也可以在新建指標的時候通過Tags變數,並且通用於其他所有指標:

var tags = new MetricTags("fromt", "db");
metrics.Measure.Gauge.SetValue(MyMetricsRegistry.Errors, tags, 10);

至此我們就完成了一個基本的指標,下面我們繼續其他型別指標。

2. 計數值(Counter)

對於HTTP型別的網站來說,存在非常多的數量需要統計記錄,所以計數值此時就特別適合這類情況,比如我們需要統計請求數量就可以利用這類指標型別,下面我們就以請求數來定義這個指標:

var requestCounter = new CounterOptions()
{
    Name = "httpRequest",
    MeasurementUnit = Unit.Calls
};

以上我們定義了一個計數指標,其中我們可以看到我們這裡使用了一個新變數MeasurementUnit主要是用於定義指標單位的,當然這個只是輔助資訊會一同輸出到結果,下面我們需要進行增加和減少,考慮到大多數情況都是減1和增1的情況:

metrics.Measure.Counter.Increment(requestCounter);

實際情況可能我們都是統計請求但是期望還能單獨統計特定介面的請求,這個時候我們在原本呼叫方式基礎上增加額外的引數:

metrics.Measure.Counter.Increment(requestCounter, "api");

如果嫌每次增長1比較慢,我們通過其函式的過載形式填寫我們希望增長的具體值。

3. 計量值(Meter)

有點類似於計數值但是相比來說,它可以提供更加豐富的資訊,比如每1、5、15分鐘的增長率等,所以對於一些需要通過增長率觀察的資料特別時候,這裡我們以請求的反應狀態碼進行記錄來體現其用途:

var httpStatusMeter = new MeterOptions()
{
    Name = "Http Status",
    MeasurementUnit = Unit.Calls
};

以上我們完成了一個指標的定義,下面我們開始使用其並且定義不同的狀態的碼的發生情況,具體如下:

metrics.Measure.Meter.Mark(httpStatusMeter, "200");
metrics.Measure.Meter.Mark(httpStatusMeter, "500");
metrics.Measure.Meter.Mark(httpStatusMeter, "401");

當然如果希望增加的數量自定控制也可以使用其提供的過載形式進行。

4. 柱狀圖(Histogram)

顧名思義,主要反應資料的分佈情況,所以這裡不在重複闡述,大家對於這種資料表現形式還是比較瞭解的,所以下面就直接以實際程式碼的實列進行介紹,便於大家的理解:

var postAndPutRequestSize = new HistogramOptions()
{
    Name = "Web Request Post & Put Size",
    MeasurementUnit = Unit.Bytes
};

以上我們定義一個體現Post和Put請求的資料尺寸的指標,下面我們利用隨機數來進行資料的模擬對其進行資料填充,便於顯示資料:

var rnd = new Random();

foreach (var i in Enumerable.Range(0, 50))
{
    var t = rnd.Next(0, 10);

    metrics.Measure.Histogram.Update(postAndPutRequestSize, t);
}

5. 時間線(Timer)

對應指標的監控閉然少不了對於時間的記錄,特別對於HTTP來說,直接影響到使用者的體驗就是響應時間,素以我們也需要時刻關於這類指標的變化情況及時做出反應,下面我們就以資料庫的響應時間的情況作為指標進行監控:

TimerOptions DatabaseTimer = new TimerOptions()
{
    Name = "Database Timer",
    MeasurementUnit = Unit.Items,
    DurationUnit = TimeUnit.Milliseconds,
    RateUnit = TimeUnit.Milliseconds
};

上面我們通過特別的屬性指定了改指標記錄時間的單位,下面我們使用其指標進行資料的記錄:

using(metrics.Measure.Timer.Time(DatabaseTimer))
{
    //to do sonmething
}

我們可以看到為了方便的記錄請求的時間,我們使用using進行涵括,並將需要記錄耗時的請求操作放入其中,在請求完成操作後就可以正確的記錄其需要的時間。

6. apdex

採用了一種標準的效能指標計算方式,用法類似與上述,這裡僅僅列舉用法:

ApdexOptions SampleApdex = new ApdexOptions
{
    Name = "Sample Apdex"
};

using(metrics.Measure.Apdex.Track(SampleApdex))
{
    Thread.Sleep(100);
}

三、高階指標

1. 平均響應

很多時候我們僅僅依靠一個指標很難完成一個實際的需求,是所以我們就需要將多個指標進行組合進行,比如我們期望得到請求次數,同時還有請求的總時間和平均響應時間等,為此我們可以特殊的指標將多個指標進行組合,具體操作如下:

var cacheHitRatioGauge = new GaugeOptions
{
    Name = "Cache Gauge",
    MeasurementUnit = Unit.Calls
};

var cacheHitsMeter = new MeterOptions
{
    Name = "Cache Hits Meter",
    MeasurementUnit = Unit.Calls
};

var databaseQueryTimer = new TimerOptions
{
    Name = "Database Query Timer",
    MeasurementUnit = Unit.Calls,
    DurationUnit = TimeUnit.Milliseconds,
    RateUnit = TimeUnit.Milliseconds
};

var cacheHits = metrics.Provider.Meter.Instance(cacheHitsMeter);
var calls = metrics.Provider.Timer.Instance(databaseQueryTimer);

var cacheHit = new Random().Next(0, 2) == 0;

using(calls.NewContext())
{
    if (cacheHit)
    {
        cacheHits.Mark(5);
    }

    Thread.Sleep(cacheHit ? 10 : 100);
}

metrics.Measure.Gauge.SetValue(cacheHitRatioGauge, () => new HitRatioGauge(cacheHits, calls, m => m.OneMinuteRate));