修复数据库连接数过多导致程序崩溃问题
This commit is contained in:
parent
871e7d47a3
commit
5bf3549522
5 changed files with 193 additions and 18 deletions
|
@ -358,5 +358,32 @@ namespace iFileProxy.Controllers
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据库连接池状态
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("GetConnectionPoolInfo")]
|
||||||
|
public async Task<ActionResult<CommonRsp>> GetConnectionPoolInfo()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var poolInfo = await _dbGateService.GetConnectionPoolInfoAsync();
|
||||||
|
return Ok(new CommonRsp
|
||||||
|
{
|
||||||
|
Retcode = 0,
|
||||||
|
Message = "success",
|
||||||
|
Data = poolInfo
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error($"获取连接池信息失败: {ex.Message}");
|
||||||
|
return Ok(new CommonRsp
|
||||||
|
{
|
||||||
|
Retcode = 1,
|
||||||
|
Message = "获取连接池信息失败"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,4 +106,81 @@ namespace iFileProxy.Models
|
||||||
public static string iFileProxy = "iFileProxy_Db";
|
public static string iFileProxy = "iFileProxy_Db";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库连接池信息
|
||||||
|
/// </summary>
|
||||||
|
public class ConnectionPoolInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 当前总连接数
|
||||||
|
/// </summary>
|
||||||
|
public long TotalConnections { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 活跃连接数
|
||||||
|
/// </summary>
|
||||||
|
public long ActiveConnections { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 空闲连接数
|
||||||
|
/// </summary>
|
||||||
|
public long SleepingConnections { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接池最大连接数
|
||||||
|
/// </summary>
|
||||||
|
public int MaxPoolSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接详情列表
|
||||||
|
/// </summary>
|
||||||
|
public List<ProcessListInfo> Connections { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MySQL 进程列表信息
|
||||||
|
/// </summary>
|
||||||
|
public class ProcessListInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 连接ID
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用户名
|
||||||
|
/// </summary>
|
||||||
|
public string User { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 主机信息
|
||||||
|
/// </summary>
|
||||||
|
public string Host { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据库名
|
||||||
|
/// </summary>
|
||||||
|
public string Db { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命令类型
|
||||||
|
/// </summary>
|
||||||
|
public string Command { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行时间(秒)
|
||||||
|
/// </summary>
|
||||||
|
public long Time { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接状态
|
||||||
|
/// </summary>
|
||||||
|
public string State { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 执行的SQL
|
||||||
|
/// </summary>
|
||||||
|
public string Info { get; set; } = string.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,18 +16,18 @@ namespace iFileProxy
|
||||||
SerilogConfig.CreateLogger();
|
SerilogConfig.CreateLogger();
|
||||||
Serilog.ILogger logger = Log.Logger.ForContext<Program>();
|
Serilog.ILogger logger = Log.Logger.ForContext<Program>();
|
||||||
|
|
||||||
Console.Write(" "); // ǿ<EFBFBD><EFBFBD>֢<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ſ<EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>־<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>벻<EFBFBD>þ<EFBFBD>
|
Console.Write(" "); // 补全日志第一行开头的空白
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD> CORS <20><><EFBFBD><EFBFBD>
|
// CORS配置
|
||||||
builder.Services.AddCors(options =>
|
builder.Services.AddCors(options =>
|
||||||
{
|
{
|
||||||
options.AddPolicy("AllowFrontend",
|
options.AddPolicy("AllowFrontend",
|
||||||
builder =>
|
builder =>
|
||||||
{
|
{
|
||||||
builder
|
builder
|
||||||
.WithOrigins("http://localhost:3000", "http://admin.gitdl.cn", "https://admin.gitdl.cn","http://47.243.56.137:50050") // ǰ<>˵<EFBFBD>ַ
|
.WithOrigins("http://localhost:3000", "http://admin.gitdl.cn", "https://admin.gitdl.cn","http://47.243.56.137:50050")
|
||||||
.AllowAnyMethod()
|
.AllowAnyMethod()
|
||||||
.AllowAnyHeader()
|
.AllowAnyHeader()
|
||||||
.AllowCredentials();
|
.AllowCredentials();
|
||||||
|
@ -55,10 +55,9 @@ namespace iFileProxy
|
||||||
|
|
||||||
builder.Services.AddSingleton<TaskManager>();
|
builder.Services.AddSingleton<TaskManager>();
|
||||||
|
|
||||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֤<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
// 添加验证服务
|
||||||
builder.Services.AddScoped<AuthService>();
|
builder.Services.AddScoped<AuthService>();
|
||||||
|
|
||||||
// <20><><EFBFBD><EFBFBD>JWT<57><54>֤
|
|
||||||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||||
.AddJwtBearer(options =>
|
.AddJwtBearer(options =>
|
||||||
{
|
{
|
||||||
|
@ -77,9 +76,8 @@ namespace iFileProxy
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
AppConfig.CheckAppConfig(app.Services);
|
// 全局错误处理中间件
|
||||||
|
app.UseMiddleware<ErrorHandlerMiddleware>();
|
||||||
LocalCacheManager localCacheManager = new(app.Services);
|
|
||||||
|
|
||||||
app.UseSerilogRequestLogging(options =>
|
app.UseSerilogRequestLogging(options =>
|
||||||
{
|
{
|
||||||
|
@ -98,17 +96,21 @@ namespace iFileProxy
|
||||||
app.UseSwaggerUI();
|
app.UseSwaggerUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><D0BC>
|
// 检查自定义配置
|
||||||
app.UseMiddleware<ErrorHandlerMiddleware>();
|
AppConfig.CheckAppConfig(app.Services);
|
||||||
|
|
||||||
|
// 初始化缓存管理器
|
||||||
|
LocalCacheManager localCacheManager = new(app.Services);
|
||||||
|
|
||||||
|
|
||||||
app.UseCors("AllowFrontend");
|
app.UseCors("AllowFrontend");
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
|
|
||||||
// <20><><EFBFBD><EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>ļ<EFBFBD>ѡ<EFBFBD><D1A1>
|
|
||||||
var defaultFilesOptions = new DefaultFilesOptions();
|
var defaultFilesOptions = new DefaultFilesOptions();
|
||||||
defaultFilesOptions.DefaultFileNames.Clear(); // <20><><EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>б<EFBFBD>
|
defaultFilesOptions.DefaultFileNames.Clear();
|
||||||
defaultFilesOptions.DefaultFileNames.Add("index.html"); // <20><><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><D4B6><EFBFBD>Ĭ<EFBFBD><C4AC><EFBFBD>ļ<EFBFBD>
|
defaultFilesOptions.DefaultFileNames.Add("index.html");
|
||||||
|
|
||||||
app.UseDefaultFiles(defaultFilesOptions);
|
app.UseDefaultFiles(defaultFilesOptions);
|
||||||
|
|
||||||
|
@ -120,7 +122,7 @@ namespace iFileProxy
|
||||||
app.Services.GetRequiredService<Dictionary<string, Dictionary<string, uint>>>(),
|
app.Services.GetRequiredService<Dictionary<string, Dictionary<string, uint>>>(),
|
||||||
AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP);
|
AppConfig.GetCurrConfig().SecurityOptions.DailyRequestLimitPerIP);
|
||||||
|
|
||||||
// <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>м<EFBFBD><EFBFBD>
|
// JWT中间件
|
||||||
app.UseMiddleware<JwtMiddleware>();
|
app.UseMiddleware<JwtMiddleware>();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
|
|
@ -115,11 +115,22 @@ namespace iFileProxy.Services
|
||||||
if (db_user == null || db_password == null || db_host == null || db_port == null)
|
if (db_user == null || db_password == null || db_host == null || db_port == null)
|
||||||
throw new NoNullAllowedException("数据库配置获取失败,不允许为空的字段出现空值");
|
throw new NoNullAllowedException("数据库配置获取失败,不允许为空的字段出现空值");
|
||||||
|
|
||||||
string db_connstr = $"server={db_host};user={db_user};database={Db.DatabaseName};port={db_port};password={db_password};Pooling=true;MaximumPoolSize=500;";
|
var builder = new MySqlConnectionStringBuilder
|
||||||
MySqlConnection conn;
|
{
|
||||||
|
Server = db_host,
|
||||||
|
UserID = db_user,
|
||||||
|
Database = Db.DatabaseName,
|
||||||
|
Port = (uint)db_port,
|
||||||
|
Password = db_password,
|
||||||
|
Pooling = true,
|
||||||
|
MinimumPoolSize = 1,
|
||||||
|
MaximumPoolSize = 50,
|
||||||
|
ConnectionLifeTime = 300 // 连接最大生命周期(秒)
|
||||||
|
};
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
conn = new MySqlConnection(db_connstr);
|
var conn = new MySqlConnection(builder.ConnectionString);
|
||||||
conn.Open();
|
conn.Open();
|
||||||
return conn;
|
return conn;
|
||||||
}
|
}
|
||||||
|
@ -900,5 +911,61 @@ namespace iFileProxy.Services
|
||||||
var users = await ExecuteQueryAsync<User>(sql, parameters);
|
var users = await ExecuteQueryAsync<User>(sql, parameters);
|
||||||
return users.FirstOrDefault();
|
return users.FirstOrDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据库连接池状态
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>连接池信息</returns>
|
||||||
|
public async Task<ConnectionPoolInfo> GetConnectionPoolInfoAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var appName = "iFileProxy"; // 程序名称
|
||||||
|
var parameters = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "@appName", $"%{appName}%" }
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取总连接数
|
||||||
|
var totalSql = @"SELECT COUNT(*)
|
||||||
|
FROM information_schema.processlist
|
||||||
|
WHERE info LIKE @appName OR host LIKE @appName";
|
||||||
|
var totalConnections = await ExecuteScalarAsync<long>(totalSql, parameters);
|
||||||
|
|
||||||
|
// 获取活跃连接数
|
||||||
|
var activeSql = @"SELECT COUNT(*)
|
||||||
|
FROM information_schema.processlist
|
||||||
|
WHERE Command != 'Sleep'
|
||||||
|
AND (info LIKE @appName OR host LIKE @appName)";
|
||||||
|
var activeConnections = await ExecuteScalarAsync<long>(activeSql, parameters);
|
||||||
|
|
||||||
|
// 获取睡眠连接数
|
||||||
|
var sleepingSql = @"SELECT COUNT(*)
|
||||||
|
FROM information_schema.processlist
|
||||||
|
WHERE Command = 'Sleep'
|
||||||
|
AND (info LIKE @appName OR host LIKE @appName)";
|
||||||
|
var sleepingConnections = await ExecuteScalarAsync<long>(sleepingSql, parameters);
|
||||||
|
|
||||||
|
// 获取连接详情
|
||||||
|
var detailSql = @"SELECT id, user, host, db, command, time, state, info
|
||||||
|
FROM information_schema.processlist
|
||||||
|
WHERE info LIKE @appName OR host LIKE @appName";
|
||||||
|
var connections = await ExecuteQueryAsync<ProcessListInfo>(detailSql, parameters);
|
||||||
|
|
||||||
|
return new ConnectionPoolInfo
|
||||||
|
{
|
||||||
|
TotalConnections = totalConnections,
|
||||||
|
ActiveConnections = activeConnections,
|
||||||
|
SleepingConnections = sleepingConnections,
|
||||||
|
MaxPoolSize = 50, // 从配置中获取的最大连接数
|
||||||
|
Connections = connections
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error($"获取连接池信息失败: {ex.Message}");
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ namespace iFileProxy.Services
|
||||||
public void CheckAndCleanCache(object state)
|
public void CheckAndCleanCache(object state)
|
||||||
{
|
{
|
||||||
// 初始化并打开一个MySQL连接 防止后续数据过多导致程序crush
|
// 初始化并打开一个MySQL连接 防止后续数据过多导致程序crush
|
||||||
var dbConn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy);
|
using var dbConn = _dbGateService.GetAndOpenDBConn(DbConfigName.iFileProxy);
|
||||||
|
|
||||||
// 获取数据库中超出生命周期的缓存数据
|
// 获取数据库中超出生命周期的缓存数据
|
||||||
string result = _dbGateService.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy);
|
string result = _dbGateService.QueryTableData($"SELECT * FROM t_tasks_info WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(update_time) > {CACHE_LIFETIME} AND (tag <> 'CLEANED' OR tag IS NULL)", DbConfigName.iFileProxy);
|
||||||
|
@ -67,6 +67,8 @@ namespace iFileProxy.Services
|
||||||
_dbGateService.UpdateTaskStatus(taskInfo,dbConn);
|
_dbGateService.UpdateTaskStatus(taskInfo,dbConn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in a new issue