ASP .NET Core App.Metrics+InfluxDB+Grafana性能監控

Grafana介紹及部署請參考這篇博客

InfluxDB

InfluxDB介紹

InfluxDB 是用Go語言編寫的一個開源分佈式時序、事件和指標數據庫,無需外部依賴
InfluxDB在DB-Engines的時序數據庫類別裏排名第一

InfluxDB相關概念

  • Database:InfluxDB可以創建數據庫,一個數據庫可以包含多個user、保存策略、schemaless ,支持隨時靈活創建mersurement
  • Measurement:相當於表的概念;
  • Tags:是一些kv的結構,標籤會被用來建立索引;
  • Fields:是保存真實數據的結構,也是kv結構,但是不會被用來建立索引;
  • Point: 代表了一條記錄,可以理解爲關係型數據庫中的一條記錄;
  • Timestamp:既然InfluxDB被稱之爲時序數據庫,少了時間是不可能的,每條記錄必須要有一個時間戳;
  • Series:是由Measurement+Tags組成的

InfluxDB優點

InfluxDB 自帶的各種特殊函數如求標準差,隨機取樣數據,統計數據變化比等,使數據統計和實時分析變得十分方便。 此外它還有如下特性:

  • 內置 HTTP 接口,使用方便
  • 數據可以打標記,這樣查詢可以很靈活
  • 類 SQL 的查詢語句
  • 安裝管理很簡單,並且讀寫數據很高效
  • 能夠實時查詢,數據在寫入時被索引後就能夠被立即查出

InfluxDB版本

InfluxDB目前推出了2.0版本,由於改動較大,所以和1.x版本並存。目前官方推薦的 穩定版本依舊是1.x版本。2.0主要的更改包括以下內容:

  • 集成了TICK組件,一鍵安裝
  • 安全集成,所有的請求都需要通過token
  • 集成管理頁面,支持更爲強大的統計和分析功能
  • 支持新的查詢語言Flux,提供更爲強大的查詢和處理功能
  • 增加了面向IoT和邊緣計算的功能,能夠在 ingestion point 彙總和分析時間序列數據
  • 啓動了新的存儲引擎InfluxDB Iox,採用Rust語言編寫

部署

新建配置和存儲目錄並寫入權限

mkdir -p /dockerdata/influxdb/{config,data}
chown -R 1000:1000   /dockerdata/influxdb
chmod -R 777  /dockerdata/influxdb

Docker部署1.0 InfluxDB

docker pull influxdb:1.8

#說明: 端口8083:web訪問端口;端口8086:數據寫入端口。
docker run -d -p 8086:8086  -p 8083:8083 --name influxdb -v /dockerdata/influxdb/data/influxdb:/var/lib/influxdb    influxdb:1.8

進入容器使用數據庫命令

#進入容器
docker exec -it  influxdb  bash
cd /usr/bin
#進入數據庫
./influx

#創建數據庫
create databases my_influxdb
#查看所有數據庫
show databases

默認不開啓Web UI和數據庫認證,訪問http://192.168.1.5:8086/會報404。

Docker部署2.0 InfluxDB

#拉最新版鏡像
docker pull influxdb

#主機上生成配置文件
docker run --rm influxdb2   influxd print-config > /dockerdata/influxdb/config/config.yml

#Run站點
# influxdb 2.X 版本存儲目錄在 /var/lib/influxdb2

docker run -d -p 8086:8086 --name influxdb2   \
  -v /dockerdata/influxdb/config/config.yml:/etc/influxdb2/config.yml \
  -v /dockerdata/influxdb/data/influxdb2:/var/lib/influxdb2 \
  -v /etc/localtime:/etc/localtime:ro \
   influxdb

瀏覽器訪問http://192.168.1.5:8086/,配置管理員賬號密碼和組織信息

快速開始

進入首頁

查看管理員Token

ASP .NET Core 集成 App.Metrics

Neget安裝以下包

App.Metrics.AspNetCore.All

#InfluxDB 1.0 安裝
App.Metrics.InfluxDB

#InfluxDB 2.0 安裝
AK.App.Metrics.Reporting.InfluxDB2

appsettings.json填入相關配置信息

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "MetricsOptions": {
    "DefaultContextLabel": "test_service",
    //"GlobalTags": {
    //  "app": "test_service123",
    //  "env": "prd444"
    //},
    "ServerTag": "192.168.1.6",
    "AppTag": "app2",
    "EnvTag": "env2",
    "Enabled": true
  },
  "MetricsWebTrackingOptions": {
    "ApdexTrackingEnabled": true,
    "ApdexTSeconds": 0.1,
    "IgnoredHttpStatusCodes": [ 302, 404 ],
    "IgnoredRoutesRegexPatterns": [],
    "OAuth2TrackingEnabled": true
  },
  "MetricEndpointsOptions": {
    "MetricsEndpointEnabled": true,
    "MetricsTextEndpointEnabled": true,
    "EnvironmentInfoEndpointEnabled": true
  },
  "MetricsReportingInfluxDbOptions": {
    "InfluxDb": {
      "CreateDataBaseIfNotExists": true,
      "BaseUri": "http://192.168.1.5:8086",
      "Database": "mydb",
      //"UserName": "rdcmonitor",
      //"Password": ":sXpvRxgxe*38"
    },
    "FlushInterval": "00:00:20"
  },
  "AllowedHosts": "*"
}

Program.cs添加配置

using App.Metrics;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);

//AddMetrics

builder.Services.AddControllers().AddMetrics();

var _configuration = builder.Configuration;

var metrics = AppMetrics.CreateDefaultBuilder().Configuration.Configure(options =>
{
    options.DefaultContextLabel = _configuration["MetricsOptions:DefaultContextLabel"];

    //options.GlobalTags = new GlobalMetricTags(Configuration.GetSection("MetricsOptions:GlobalTags").Get<Dictionary<string, string>>());
    options.AddServerTag(_configuration["MetricsOptions:ServerTag"]);
    options.AddAppTag(_configuration["MetricsOptions:AppTag"]);
    options.AddEnvTag(_configuration["MetricsOptions:EnvTag"]);
}).Report.ToInfluxDb(options =>
{
    options.InfluxDb.BaseUri = new Uri(_configuration["MetricsReportingInfluxDbOptions:InfluxDb:BaseUri"]);
    options.InfluxDb.Database = _configuration["MetricsReportingInfluxDbOptions:InfluxDb:Database"];

    //1.0認證 配置用戶名密碼,默認沒有
    //options.InfluxDb.UserName = username;
    //options.InfluxDb.Password = password;

    options.InfluxDb.CreateDataBaseIfNotExists = bool.Parse(_configuration["MetricsReportingInfluxDbOptions:InfluxDb:CreateDataBaseIfNotExists"]);
    options.FlushInterval = TimeSpan.Parse(_configuration["MetricsReportingInfluxDbOptions:FlushInterval"]);
}).Build();

builder.Services.AddMetrics(metrics);
//添加報表
builder.Services.AddMetricsReportingHostedService();
builder.Services.AddMetricsTrackingMiddleware(_configuration);
builder.Services.AddMetricsEndpoints(_configuration);


var app = builder.Build();

// Configure the HTTP request pipeline.

app.UseAuthorization();

app.MapControllers();


//UseMetrics
app.UseMetricsAllEndpoints();
app.UseMetricsAllMiddleware();


app.Run();

Grafana查看數據

InfluxDb 1.0添加數據源保存


添加面板,默認模板地址:https://grafana.com/dashboards/2125

根據envapp(和配置文件對應)查看面板

InfluxDb 2.0添加數據源保存,目前沒有Grafana面板。


健康檢查

簡介

健康檢查,其實這個名稱已經很明確了,它是檢查你的應用程序是否健康運行的一種方式。隨着當前各類項目越來越多的應用程序正在轉向微服務式架構,健康檢查就變得尤爲關鍵。雖然微服務體系結構具有許多好處,但其中一個缺點就是爲了確保所有這些服務都正常運行的操作開銷更高。你不在是監視一個龐大的整體項目的健康狀況,而是需要監控許多不同服務的狀態,甚至這些服務通常只負責一件事情。健康檢查(Heatlh Checks)通常與一些服務發現工具結合使用,如Consul ,來監控您的微服務器,來觀測您的服務是否健康運行。

實現

健康檢查有很多種不同的方法,但最常見的方法是將HTTP端點暴露給專門用於健康檢查的應用程序。一般來說,如果一切情況都很好,你的服務將返回200的狀態碼,然而任何非200的代碼則意味着出現問題。例如,如果發生錯誤,你可能會返回500以及一些出錯的JSON信息。

常見情況

你的健康檢查將基於你的應用程序或者你的微服務主要在做寫什麼事情,就檢查什麼.

不過我們也可以舉例一些常見的健康檢查內容:

  • 檢查我的服務可以連接到數據庫嗎?
  • 檢查我的服務可以查詢第三方API嗎?
    • 可能做一些只讀操作
  • 我的服務可以訪問文件系統嗎(IO是否正常)?
  • 檢查我的服務佔用的內存或CPU是否高於某個閾值?

下面我們就來講解一下,如何使用App Metrics來實現我們的健康檢查

效果如圖:
App Metrics中的健康檢查分爲3種狀態:

  1. 健康(綠),
  2. 亞健康(黃)
  3. 不健康(紅)

編碼

安裝Neget包

App.Metrics.AspNetCore.Health
App.Metrics.Health.Checks.Http
App.Metrics.Health.Checks.Network
App.Metrics.Health.Checks.Process
App.Metrics.Health.Reporting.Metrics

在項目中新建一個HealthChecks文件夾,新建一個RedisHealthCheck

using App.Metrics.Health;

namespace WebApplication2
{
    public class RedisHealthCheck : HealthCheck
    {
        //面板名稱;十秒檢查一次
        public RedisHealthCheck() : base("Redis", TimeSpan.FromSeconds(10)) { }

        protected override ValueTask<HealthCheckResult> CheckAsync(CancellationToken cancellationToken = default)
        {
            try
            {
                if (true)
                {
                    //健康
                    return new ValueTask<HealthCheckResult>(HealthCheckResult.Healthy());
                }
                else
                {
                    //不健康
                    return new ValueTask<HealthCheckResult>(HealthCheckResult.Unhealthy());
                }
            }
            catch
            {
                return new ValueTask<HealthCheckResult>(HealthCheckResult.Unhealthy());
            }
        }
    }
}

Program.cs添加健康檢查服務

builder.Services.AddHealth(SetupHealth(metrics));



static IHealthBuilder SetupHealth(IMetrics metrics)
{

    //var healthBuilder = serviceProvider.GetService<IHealthBuilder>();
    var healthBuilder = new HealthBuilder();
    var health = new HealthBuilder().Configuration
                              .Configure(p =>
                              {
                                  p.Enabled = true;
                                  p.ReportingEnabled = true;
                              })
                              .Report.ToMetrics(metrics)
                              //自定義Redis檢查
                              .HealthChecks.AddCheck<RedisHealthCheck>()
                              //檢測專用內存佔用量是否超過閥值(2G)
                              .HealthChecks.AddProcessPrivateMemorySizeCheck("Private Memory Size", (2048L * 1024L) * 1024L)
                              //檢測虛擬內存佔用是否超過閥值(2G)
                              .HealthChecks.AddProcessVirtualMemorySizeCheck("Virtual Memory Size", (2048L * 1024L) * 1024L)
                              //檢測佔用內存是否超過2G
                              .HealthChecks.AddProcessPhysicalMemoryCheck("Working Set", (2048L * 1024L) * 1024L)
                              .HealthChecks.AddPingCheck("google ping", "google.com", TimeSpan.FromSeconds(10))
                              .HealthChecks.AddHttpGetCheck("github", new Uri("https://github.com/"), TimeSpan.FromSeconds(10))
                              .Build();


    var scheduler = new AppMetricsTaskScheduler(TimeSpan.FromSeconds(5), async () =>
                            {
                                //多線程發送報告
                                //await Task.WhenAll(metricsRoot.ReportRunner.RunAllAsync());

                                var healthStatus = await health.HealthCheckRunner.ReadAsync();

                                //using (var stream = new MemoryStream())
                                //{
                                //    await health.DefaultOutputHealthFormatter
                                //                .WriteAsync(stream, healthStatus);
                                //    var result = Encoding.UTF8.GetString(stream.ToArray());
                                //    Console.WriteLine(result);
                                //}
                                //發送報告
                                foreach (var reporter in health.Reporters)
                                    await reporter.ReportAsync(health.Options, healthStatus);
                            });
    scheduler.Start();
    return healthBuilder;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章