1.為什麼需要監控服務
監控服務的所屬伺服器硬體(如cpu,記憶體,磁碟I/O等)指標、服務本身的(如gc頻率、執行緒池大小、鎖爭用情況、請求、響應、自定義業務指標),對於以前的小型單體服務來說,確實沒什麼必要,但對於中大型專案,尤其那些群集部署顯得尤為重要、尤其是現在的微服務架構,服務眾多,而且很多服務都是群集部署,我們更是需要實時知道每一個服務所屬的範例(pod,伺服器)的執行、請求異常、自定義業務監控指標等情況。
2.監控方案
監控方案因公司而異,沒有固定的套路,不一定複雜就好用,越複雜學習、維護、支出成本就越高,適合自己團隊就好,拋磚引玉我們之前使用過的方案:
自己的伺服器windows群集,.net core微服務架構,使用Telegraf在每臺機伺服器上進行採集cpu,記憶體,磁碟IO等等硬體指標資料和sqlserver、redis、rabbitmq等指標資訊,使用Prometheus來採集.net core服務的請求相關的資料,無論是硬體指標還是軟體指標,統一傳送到時序資料庫InfulxDB種,使用開源的報表程式Grafana來進行實時報表監控,通過Grafana的Alert條件觸發webhook來將報警的資料資訊組織好格式後,傳送到我們自己寫的一個服務接收,然後通過我們研發的通知訂閱中心來傳送給訂閱者郵件、簡訊、企業微信、桌面等告警提示;
騰訊雲Linux伺服器,.net core微服務架構,基於k8s編排管理的docker叢集,既然是雲,很多硬體指標都是自帶的監控,使用Prometheus監控叢集下的所有服務的異常請求,Rabbitmq,Redis等等中介軟體指標資訊,這次是基於Prometheus自帶的時許資料庫,使用其altermanger元件進行告警,全部Prometheus設定和自動發現新pod能力,都由牛逼的運維團隊完成。
3.Prometheus
本文中,我們主要來說說目前非常流行的監控中介軟體Prometheus,基於docker的搭建、設定、基本指標採集、自定義業務指標採集。
Prometheus是一個開源的現代化的、支援雲原生的系統監控與告警系統,2012年由前谷歌員工開發並做為社群開源專案開發,2015年正式釋出,2016年加入雲原生計算基金會CNCF,熱度僅次於K8S。git地址。
已經很多知名的三方廠商已經基於Prometheus做成了匯入器node exporter,比如linux系統,MYSQL資料庫,Redis等等非常多的中介軟體,有了這些匯入器,我們直接可以使用,非常豐富的監控指標人家已經為我們做好了。等下,我們演示以下使用linux的匯入器來監控linux系統指標。
上面是官方給出的生態元件圖,Prometheus整個生態圈組成主要包括prometheus server,Exporter,pushgateway,alertmanager,grafana,Web ui介面,Prometheus server由三個部分組成,Retrieval,Storage,PromQL;
工作流程,Prometheus server定期從活躍的目標主機上通過http pull的方式拉取指標資料,目標主機可以通過prometheus的組態檔進行設定或者通過服務發現方式來發現目標主機;也可以通過pushGateway元件,從目標主機推播該元件,Prometheus server再定時從該元件拉取指標資料;
4.Prometheus基於docker的搭建和監控
docker pull prom/node-exporter
docker run --name=node-exporter -p 9100:9100 -itd prom/node-exporter
mkdir /opt/prometheus
cd /opt/prometheus/
vim prometheus.yml
global:
scrape_interval: 60s
evaluation_interval: 60s
scrape_configs:
- job_name: linuxNode1 --目標任務名稱
static_configs:
- targets: ['ip:9100'] --可以是多臺
labels:
instance: linux1 --指標維度
5.啟動prometheus容器
docker run -d -p 9090:9090 -v /opt/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml --name prometheus prom/prometheus:latest
啟動成功後,prometheus的webui也可以使用了,瀏覽器輸入http://IP:9090/targets
5.Grafana
官方說明,grafana是用於視覺化大型測量資料的開源程式,他提供了強大和優雅的方式去建立、共用、瀏覽資料。用過之後確實強大,可設定性靈活,現成的主流中介軟體基於prometheus的報表模板非常豐富。
docker pull grafana/grafana
docker run -d -p 3000:3000 --name=jmeterGrafana grafana/grafana
瀏覽器存取:http://ip:3000(賬號密碼都是:admin)
選擇資料來源
至此,我們的linux伺服器的報表監控好了,接下來,我們來監控.net core服務的基本指標、請求、自定義業務資料。
6..net core整合prometheus
//收集一些服務基本資訊,比如執行緒數,記憶體使用,控制程式碼,3個GC得回收次數統計
app.UseMetricServer();
啟動程式存取http://localhost:5000/metrics
做為API服務,我們當然要收集http請求,請求狀態,耗時,次數這些
//收集一些服務基本資訊,比如執行緒數,記憶體使用,控制程式碼,3個GC得回收次數統計
app.UseMetricServer();
//收集http請求和計數監控,比如總請求數,每次請求得耗時
app.UseHttpMetrics();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//Program下main方法,為了減少效能開銷,可以設定如下
DotNetRuntimeStatsBuilder
.Customize()
//每5個事件個採集一個
.WithContentionStats(sampleRate: SampleEvery.FiveEvents)
//每10事件採集一個
.WithJitStats(sampleRate: SampleEvery.TenEvents)
.WithThreadPoolStats()
.WithGcStats()
.StartCollecting();
再次執行會看到更多的指標了
這麼多指標,維度的監控在prometheus原生UI上通過過濾可以看到響應的資料和報表,比如我們要看服務執行總記憶體,通過指標key:dotnet_total_memory_bytes,去webui上搜尋:
我們找到一個模板,複製id用上文grafana匯入模板的方法,匯入進去,看看:
嗯,看上去好像不咋地,很多指標顯示不出來,實際專案裡,我們知道了指標資料,都是基於grafana自己設定要看的報表,下文我們繼續來看看,怎麼在.net core中基於promethues自定義一些指標收集,並且利用grafana來設定響應的報表。
7.自定義指標收集與設定報表
通過上文的metrics指標資料,指標資料其實就是key value結構,只不過key中有label增加維度,並且每一個鍵值對都有響應的指標型別,prometheus的metrics有以下4種主要型別:
public class PrometheusMetricsHub
{
/// <summary>
/// 監控計數器維度統計容器
/// </summary>
public Dictionary<string, Counter> Counters { get; set; } = new Dictionary<string, Counter>();
/// <summary>
/// 監控儀表盤維度統計容器
/// </summary>
public Dictionary<string, Gauge> Gauges { get; set; } = new Dictionary<string, Gauge>();
/// <summary>
/// 建立計數器容器
/// </summary>
/// <param name="key"></param>
/// <param name="desc"></param>
/// <returns></returns>
public void CreateCounter(string key, string desc)
{
if (!this.Counters.ContainsKey(key))
this.Counters.Add(key, Metrics.CreateCounter(key, desc));
}
/// <summary>
/// 建立儀表盤容器
/// </summary>
/// <param name="key"></param>
/// <param name="desc"></param>
/// <returns></returns>
public void CreateGauge(string key, string desc)
{
if (!this.Gauges.ContainsKey(key))
this.Gauges.Add(key, Metrics.CreateGauge(key, desc));
}
/// <summary>
/// 根據維度型別獲取監控範例
/// </summary>
/// <typeparam name="TContainer"></typeparam>
/// <param name="prometheusEnum"></param>
/// <param name="key"></param>
/// <returns></returns>
public TContainer GetContainer<TContainer>(PrometheusEnum prometheusEnum, string key) where TContainer : class
{
if (prometheusEnum == PrometheusEnum.Counter && this.Counters.ContainsKey(key))
return this.Counters.GetValueOrDefault(key) as TContainer;
if (prometheusEnum == PrometheusEnum.Gauge && this.Gauges.ContainsKey(key))
return this.Gauges.GetValueOrDefault(key) as TContainer;
return null;
}
public static class PrometheusMetricsHubExtenisons
{
public static IServiceCollection AddPrometheusMetricsHub(this IServiceCollection services,Action<PrometheusMetricsHub> buildAction)
{
var hub = new PrometheusMetricsHub();
buildAction(hub);
services.AddSingleton<PrometheusMetricsHub>(hub);
return services;
}
}
//註冊監控
services.AddPrometheusMetricsHub(hub =>
{
hub.CreateCounter("demoCounter", "測試計數器");
hub.CreateGauge("demoGauge", "測試儀表盤");
});
public class PrometheusRequestMiddleware
{
private readonly RequestDelegate _next;
private readonly PrometheusMetricsHub _prometheusMetricsHub;
public PrometheusRequestMiddleware(RequestDelegate next, PrometheusMetricsHub prometheusMetricsHub)
{
_next = next;
_prometheusMetricsHub = prometheusMetricsHub;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
//增加測試資料
var counter = _prometheusMetricsHub.GetContainer<Counter>(Models.PrometheusEnum.Counter, "demoCounter");
var gauge = _prometheusMetricsHub.GetContainer<Gauge>(Models.PrometheusEnum.Gauge, "demoGauge");
counter.Inc();
gauge.Inc();
await _next(context);
}
finally
{
}
}
}
app.UseMiddleware<PrometheusRequestMiddleware>();
由上圖所見,我們自定義的指標監控完成。
8.關於Prometheus高可用
Prometheus本身不支援群集部署,也就是說本身沒法動態水平擴容,其實其本身的效能非常高,很少有撐不住情況,我們擔心的是硬碟容量問題,假設真的是超級大量的指標資料,怎麼辦呢,下面有幾個方案,也歡迎留言討論:
9.一些問題