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
根据env
和app
(和配置文件对应)查看面板
InfluxDb 2.0
添加数据源保存,目前没有Grafana面板。
健康检查
健康检查可以参考这篇博客
下面我们就来讲解一下,如何使用App Metrics来实现我们的健康检查
效果如图:
App Metrics中的健康检查分为3种状态:
- 健康(绿),
- 亚健康(黄)
- 不健康(红)
健康检查有三个登记
- Healthy 健康
- Unhealthy 不良
- Degraded 降级
编码实现
安装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;
}
程序自身健康检查
using App.Metrics.Health;
namespace WebApplication.HealthChecks
{
public class DelayStartupHealthCheck : HealthCheck
{
public DelayStartupHealthCheck()
: base("DelayStartup", TimeSpan.FromSeconds(5)) { }
protected override ValueTask<HealthCheckResult> CheckAsync(CancellationToken cancellationToken = default(CancellationToken))
{
if (DelayStartup.StartupReady)
{
return new ValueTask<HealthCheckResult>(HealthCheckResult.Healthy());
}
return new ValueTask<HealthCheckResult>(HealthCheckResult.Unhealthy());
}
}
public class DelayStartup
{
public static bool StartupReady { get; private set; } = false;
private static long DelaySeconds = 60;
private static Semaphore semaphore = new Semaphore(0, 1);
static DelayStartup()
{
try
{
//IConfiguration configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
//DelaySeconds = int.Parse(configuration["App:DelayStartup"]);
DelaySeconds = 0;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
DelaySeconds = 0;
}
if (DelaySeconds > 0)
{
Startup();
}
else
{
StartupReady = true;
}
}
private static void Startup()
{
DateTime start = DateTime.Now;
Task.Factory.StartNew(() =>
{
while (true)
{
if (DateTime.Now.Subtract(start).TotalSeconds >= DelaySeconds)
{
StartupReady = true;
Console.WriteLine("DelayStartup StartupReady");
break;
}
Console.WriteLine("DelayStartup Checking");
semaphore.WaitOne(2000);
}
});
}
}
}
集成 Microsoft.Extensions.Diagnostics.HealthChecks
Microsoft.Extensions.Diagnostics.HealthChecks
使用可以参考这篇博客
Neget依赖还是上面哪那些包
新建健康检查类
using Microsoft.Extensions.Diagnostics.HealthChecks;
using System.Net.Http;
namespace WebApplication2.HealthChecks
{
public class RemoteHealthCheck : IHealthCheck
{
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken())
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("https://www.baidu.com");
if (response.IsSuccessStatusCode)
{
return HealthCheckResult.Healthy($"API is running.");
}
return HealthCheckResult.Unhealthy("API is not running");
}
}
}
public class DatabaseHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken =
default)
{
try
{
return Task.FromResult(HealthCheckResult.Healthy());
}
catch (Exception ex)
{
return Task.FromResult(HealthCheckResult.Unhealthy("DB is not Healthy", ex));
}
}
}
}
在Program.cs
添加健康检查服务
//基于上面的代码添加配置
//30S轮询一次
builder.Services.AddHealthChecks()
.AddCheck<RemoteHealthCheck>(nameof(RemoteHealthCheck))
.AddCheck<DatabaseHealthCheck>(nameof(DatabaseHealthCheck));
builder.Services.AddAppMetricsHealthPublishing();
……
//app.UseHealthChecks("/health");
app.MapHealthChecks("/health");
运行程序然后访问 /health
,会主动发起健康检查
查看面板
相关链接
https://www.cnblogs.com/yaozhenfa/p/12291749.html
https://www.cnblogs.com/edisonchou/p/integrated_performance_monitoring_foundation.html