2026-01-30 01:00:49 +08:00
|
|
|
|
package controller
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"os"
|
|
|
|
|
|
"runtime"
|
2026-02-04 17:36:07 +08:00
|
|
|
|
"time"
|
2026-01-30 01:00:49 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/QuantumNous/new-api/common"
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// PerformanceStats 性能统计信息
|
|
|
|
|
|
type PerformanceStats struct {
|
|
|
|
|
|
// 缓存统计
|
|
|
|
|
|
CacheStats common.DiskCacheStats `json:"cache_stats"`
|
|
|
|
|
|
// 系统内存统计
|
|
|
|
|
|
MemoryStats MemoryStats `json:"memory_stats"`
|
|
|
|
|
|
// 磁盘缓存目录信息
|
|
|
|
|
|
DiskCacheInfo DiskCacheInfo `json:"disk_cache_info"`
|
|
|
|
|
|
// 磁盘空间信息
|
2026-02-04 21:13:49 +08:00
|
|
|
|
DiskSpaceInfo common.DiskSpaceInfo `json:"disk_space_info"`
|
2026-01-30 01:00:49 +08:00
|
|
|
|
// 配置信息
|
|
|
|
|
|
Config PerformanceConfig `json:"config"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// MemoryStats 内存统计
|
|
|
|
|
|
type MemoryStats struct {
|
|
|
|
|
|
// 已分配内存(字节)
|
|
|
|
|
|
Alloc uint64 `json:"alloc"`
|
|
|
|
|
|
// 总分配内存(字节)
|
|
|
|
|
|
TotalAlloc uint64 `json:"total_alloc"`
|
|
|
|
|
|
// 系统内存(字节)
|
|
|
|
|
|
Sys uint64 `json:"sys"`
|
|
|
|
|
|
// GC 次数
|
|
|
|
|
|
NumGC uint32 `json:"num_gc"`
|
|
|
|
|
|
// Goroutine 数量
|
|
|
|
|
|
NumGoroutine int `json:"num_goroutine"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DiskCacheInfo 磁盘缓存目录信息
|
|
|
|
|
|
type DiskCacheInfo struct {
|
|
|
|
|
|
// 缓存目录路径
|
|
|
|
|
|
Path string `json:"path"`
|
|
|
|
|
|
// 目录是否存在
|
|
|
|
|
|
Exists bool `json:"exists"`
|
|
|
|
|
|
// 文件数量
|
|
|
|
|
|
FileCount int `json:"file_count"`
|
|
|
|
|
|
// 总大小(字节)
|
|
|
|
|
|
TotalSize int64 `json:"total_size"`
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PerformanceConfig 性能配置
|
|
|
|
|
|
type PerformanceConfig struct {
|
|
|
|
|
|
// 是否启用磁盘缓存
|
|
|
|
|
|
DiskCacheEnabled bool `json:"disk_cache_enabled"`
|
|
|
|
|
|
// 磁盘缓存阈值(MB)
|
|
|
|
|
|
DiskCacheThresholdMB int `json:"disk_cache_threshold_mb"`
|
|
|
|
|
|
// 磁盘缓存最大大小(MB)
|
|
|
|
|
|
DiskCacheMaxSizeMB int `json:"disk_cache_max_size_mb"`
|
|
|
|
|
|
// 磁盘缓存路径
|
|
|
|
|
|
DiskCachePath string `json:"disk_cache_path"`
|
|
|
|
|
|
// 是否在容器中运行
|
|
|
|
|
|
IsRunningInContainer bool `json:"is_running_in_container"`
|
2026-02-04 21:13:49 +08:00
|
|
|
|
|
|
|
|
|
|
// MonitorEnabled 是否启用性能监控
|
|
|
|
|
|
MonitorEnabled bool `json:"monitor_enabled"`
|
|
|
|
|
|
// MonitorCPUThreshold CPU 使用率阈值(%)
|
|
|
|
|
|
MonitorCPUThreshold int `json:"monitor_cpu_threshold"`
|
|
|
|
|
|
// MonitorMemoryThreshold 内存使用率阈值(%)
|
|
|
|
|
|
MonitorMemoryThreshold int `json:"monitor_memory_threshold"`
|
|
|
|
|
|
// MonitorDiskThreshold 磁盘使用率阈值(%)
|
|
|
|
|
|
MonitorDiskThreshold int `json:"monitor_disk_threshold"`
|
2026-01-30 01:00:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetPerformanceStats 获取性能统计信息
|
|
|
|
|
|
func GetPerformanceStats(c *gin.Context) {
|
2026-02-04 17:36:07 +08:00
|
|
|
|
// 不再每次获取统计都全量扫描磁盘,依赖原子计数器保证性能
|
|
|
|
|
|
// 仅在系统启动或显式清理时同步
|
2026-01-30 01:00:49 +08:00
|
|
|
|
cacheStats := common.GetDiskCacheStats()
|
|
|
|
|
|
|
|
|
|
|
|
// 获取内存统计
|
|
|
|
|
|
var memStats runtime.MemStats
|
|
|
|
|
|
runtime.ReadMemStats(&memStats)
|
|
|
|
|
|
|
|
|
|
|
|
// 获取磁盘缓存目录信息
|
|
|
|
|
|
diskCacheInfo := getDiskCacheInfo()
|
|
|
|
|
|
|
|
|
|
|
|
// 获取配置信息
|
|
|
|
|
|
diskConfig := common.GetDiskCacheConfig()
|
2026-02-04 21:13:49 +08:00
|
|
|
|
monitorConfig := common.GetPerformanceMonitorConfig()
|
2026-01-30 01:00:49 +08:00
|
|
|
|
config := PerformanceConfig{
|
2026-02-04 21:13:49 +08:00
|
|
|
|
DiskCacheEnabled: diskConfig.Enabled,
|
|
|
|
|
|
DiskCacheThresholdMB: diskConfig.ThresholdMB,
|
|
|
|
|
|
DiskCacheMaxSizeMB: diskConfig.MaxSizeMB,
|
|
|
|
|
|
DiskCachePath: diskConfig.Path,
|
|
|
|
|
|
IsRunningInContainer: common.IsRunningInContainer(),
|
|
|
|
|
|
MonitorEnabled: monitorConfig.Enabled,
|
|
|
|
|
|
MonitorCPUThreshold: monitorConfig.CPUThreshold,
|
|
|
|
|
|
MonitorMemoryThreshold: monitorConfig.MemoryThreshold,
|
|
|
|
|
|
MonitorDiskThreshold: monitorConfig.DiskThreshold,
|
2026-01-30 01:00:49 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取磁盘空间信息
|
2026-02-04 21:13:49 +08:00
|
|
|
|
// 使用缓存的系统状态,避免频繁调用系统 API
|
|
|
|
|
|
systemStatus := common.GetSystemStatus()
|
|
|
|
|
|
diskSpaceInfo := common.DiskSpaceInfo{
|
|
|
|
|
|
UsedPercent: systemStatus.DiskUsage,
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果需要详细信息,可以按需获取,或者扩展 SystemStatus
|
|
|
|
|
|
// 这里为了保持接口兼容性,我们仍然调用 GetDiskSpaceInfo,但注意这可能会有性能开销
|
|
|
|
|
|
// 考虑到 GetPerformanceStats 是管理接口,频率较低,直接调用是可以接受的
|
|
|
|
|
|
// 但为了一致性,我们也可以考虑从 SystemStatus 中获取部分信息
|
|
|
|
|
|
diskSpaceInfo = common.GetDiskSpaceInfo()
|
2026-01-30 01:00:49 +08:00
|
|
|
|
|
|
|
|
|
|
stats := PerformanceStats{
|
|
|
|
|
|
CacheStats: cacheStats,
|
|
|
|
|
|
MemoryStats: MemoryStats{
|
|
|
|
|
|
Alloc: memStats.Alloc,
|
|
|
|
|
|
TotalAlloc: memStats.TotalAlloc,
|
|
|
|
|
|
Sys: memStats.Sys,
|
|
|
|
|
|
NumGC: memStats.NumGC,
|
|
|
|
|
|
NumGoroutine: runtime.NumGoroutine(),
|
|
|
|
|
|
},
|
|
|
|
|
|
DiskCacheInfo: diskCacheInfo,
|
|
|
|
|
|
DiskSpaceInfo: diskSpaceInfo,
|
|
|
|
|
|
Config: config,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"success": true,
|
|
|
|
|
|
"data": stats,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-02-04 17:36:07 +08:00
|
|
|
|
// ClearDiskCache 清理不活跃的磁盘缓存
|
2026-01-30 01:00:49 +08:00
|
|
|
|
func ClearDiskCache(c *gin.Context) {
|
2026-02-04 17:36:07 +08:00
|
|
|
|
// 清理超过 10 分钟未使用的缓存文件
|
|
|
|
|
|
// 10 分钟是一个安全的阈值,确保正在进行的请求不会被误删
|
|
|
|
|
|
err := common.CleanupOldDiskCacheFiles(10 * time.Minute)
|
|
|
|
|
|
if err != nil {
|
2026-01-30 01:00:49 +08:00
|
|
|
|
common.ApiError(c, err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"success": true,
|
2026-02-04 17:36:07 +08:00
|
|
|
|
"message": "不活跃的磁盘缓存已清理",
|
2026-01-30 01:00:49 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ResetPerformanceStats 重置性能统计
|
|
|
|
|
|
func ResetPerformanceStats(c *gin.Context) {
|
|
|
|
|
|
common.ResetDiskCacheStats()
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"success": true,
|
|
|
|
|
|
"message": "统计信息已重置",
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ForceGC 强制执行 GC
|
|
|
|
|
|
func ForceGC(c *gin.Context) {
|
|
|
|
|
|
runtime.GC()
|
|
|
|
|
|
|
|
|
|
|
|
c.JSON(http.StatusOK, gin.H{
|
|
|
|
|
|
"success": true,
|
|
|
|
|
|
"message": "GC 已执行",
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// getDiskCacheInfo 获取磁盘缓存目录信息
|
|
|
|
|
|
func getDiskCacheInfo() DiskCacheInfo {
|
2026-02-04 17:15:24 +08:00
|
|
|
|
// 使用统一的缓存目录
|
|
|
|
|
|
dir := common.GetDiskCacheDir()
|
2026-01-30 01:00:49 +08:00
|
|
|
|
|
|
|
|
|
|
info := DiskCacheInfo{
|
|
|
|
|
|
Path: dir,
|
|
|
|
|
|
Exists: false,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
entries, err := os.ReadDir(dir)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return info
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
info.Exists = true
|
|
|
|
|
|
info.FileCount = 0
|
|
|
|
|
|
info.TotalSize = 0
|
|
|
|
|
|
|
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
|
|
if entry.IsDir() {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
info.FileCount++
|
|
|
|
|
|
if fileInfo, err := entry.Info(); err == nil {
|
|
|
|
|
|
info.TotalSize += fileInfo.Size()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return info
|
|
|
|
|
|
}
|