mirror of
https://github.com/woodchen-ink/proxy-go.git
synced 2025-07-18 16:41:54 +08:00
refactor(metrics): 优化指标收集和内存管理
- 修改路径统计数据结构为指针类型,提高性能 - 使用原子操作方法替换旧的原子操作 - 添加内存释放和垃圾回收机制 - 限制路径统计数量,只保留前20个路径 - 优化指标保存和文件清理逻辑,减少内存使用
This commit is contained in:
parent
4276709b3f
commit
095b087fd8
@ -165,15 +165,17 @@ func (c *Collector) RecordRequest(path string, status int, latency time.Duration
|
|||||||
// 更新路径统计
|
// 更新路径统计
|
||||||
c.pathStatsMutex.Lock()
|
c.pathStatsMutex.Lock()
|
||||||
if value, ok := c.pathStats.Load(path); ok {
|
if value, ok := c.pathStats.Load(path); ok {
|
||||||
stat := value.(models.PathStats)
|
stat, ok := value.(*models.PathStats)
|
||||||
stat.Requests.Store(stat.Requests.Load() + 1)
|
if ok {
|
||||||
stat.Bytes.Store(stat.Bytes.Load() + bytes)
|
stat.Requests.Add(1)
|
||||||
stat.LatencySum.Store(stat.LatencySum.Load() + int64(latency))
|
stat.Bytes.Add(bytes)
|
||||||
|
stat.LatencySum.Add(int64(latency))
|
||||||
if status >= 400 {
|
if status >= 400 {
|
||||||
stat.Errors.Store(stat.Errors.Load() + 1)
|
stat.Errors.Add(1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
newStat := models.PathStats{
|
newStat := &models.PathStats{
|
||||||
Requests: atomic.Int64{},
|
Requests: atomic.Int64{},
|
||||||
Bytes: atomic.Int64{},
|
Bytes: atomic.Int64{},
|
||||||
LatencySum: atomic.Int64{},
|
LatencySum: atomic.Int64{},
|
||||||
@ -262,7 +264,10 @@ func (c *Collector) GetStats() map[string]interface{} {
|
|||||||
pathStatsMap := make(map[string]interface{})
|
pathStatsMap := make(map[string]interface{})
|
||||||
c.pathStats.Range(func(key, value interface{}) bool {
|
c.pathStats.Range(func(key, value interface{}) bool {
|
||||||
path := key.(string)
|
path := key.(string)
|
||||||
stats := value.(models.PathStats)
|
stats, ok := value.(*models.PathStats)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
requestCount := stats.Requests.Load()
|
requestCount := stats.Requests.Load()
|
||||||
if requestCount > 0 {
|
if requestCount > 0 {
|
||||||
latencySum := stats.LatencySum.Load()
|
latencySum := stats.LatencySum.Load()
|
||||||
@ -289,7 +294,11 @@ func (c *Collector) GetStats() map[string]interface{} {
|
|||||||
AvgLatency string
|
AvgLatency string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 限制路径统计的数量,只保留前N个
|
||||||
|
maxPaths := 20 // 只保留前20个路径
|
||||||
var pathStatsList []pathStat
|
var pathStatsList []pathStat
|
||||||
|
|
||||||
|
// 先将pathStatsMap转换为pathStatsList
|
||||||
for path, statData := range pathStatsMap {
|
for path, statData := range pathStatsMap {
|
||||||
if stat, ok := statData.(map[string]interface{}); ok {
|
if stat, ok := statData.(map[string]interface{}); ok {
|
||||||
pathStatsList = append(pathStatsList, pathStat{
|
pathStatsList = append(pathStatsList, pathStat{
|
||||||
@ -303,6 +312,9 @@ func (c *Collector) GetStats() map[string]interface{} {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放pathStatsMap内存
|
||||||
|
pathStatsMap = nil
|
||||||
|
|
||||||
// 按请求数降序排序,请求数相同时按路径字典序排序
|
// 按请求数降序排序,请求数相同时按路径字典序排序
|
||||||
sort.Slice(pathStatsList, func(i, j int) bool {
|
sort.Slice(pathStatsList, func(i, j int) bool {
|
||||||
if pathStatsList[i].Requests != pathStatsList[j].Requests {
|
if pathStatsList[i].Requests != pathStatsList[j].Requests {
|
||||||
@ -311,6 +323,11 @@ func (c *Collector) GetStats() map[string]interface{} {
|
|||||||
return pathStatsList[i].Path < pathStatsList[j].Path
|
return pathStatsList[i].Path < pathStatsList[j].Path
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 只保留前maxPaths个
|
||||||
|
if len(pathStatsList) > maxPaths {
|
||||||
|
pathStatsList = pathStatsList[:maxPaths]
|
||||||
|
}
|
||||||
|
|
||||||
// 转换为有序的map
|
// 转换为有序的map
|
||||||
orderedPathStats := make([]map[string]interface{}, len(pathStatsList))
|
orderedPathStats := make([]map[string]interface{}, len(pathStatsList))
|
||||||
for i, ps := range pathStatsList {
|
for i, ps := range pathStatsList {
|
||||||
@ -378,7 +395,7 @@ func (c *Collector) SaveMetrics(stats map[string]interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将统计数据保存到文件
|
// 将统计数据保存到文件
|
||||||
data, err := json.MarshalIndent(stats, "", " ")
|
data, err := json.Marshal(stats) // 使用Marshal而不是MarshalIndent来减少内存使用
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to marshal metrics data: %v", err)
|
return fmt.Errorf("failed to marshal metrics data: %v", err)
|
||||||
}
|
}
|
||||||
@ -399,6 +416,10 @@ func (c *Collector) SaveMetrics(stats map[string]interface{}) error {
|
|||||||
log.Printf("[Metrics] Warning: Failed to cleanup old metrics files: %v", err)
|
log.Printf("[Metrics] Warning: Failed to cleanup old metrics files: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放内存
|
||||||
|
data = nil
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
c.lastSaveTime = time.Now()
|
c.lastSaveTime = time.Now()
|
||||||
log.Printf("[Metrics] Saved metrics to %s", filename)
|
log.Printf("[Metrics] Saved metrics to %s", filename)
|
||||||
return nil
|
return nil
|
||||||
@ -455,6 +476,9 @@ func (c *Collector) cleanupOldMetricsFiles() error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放statsFiles内存
|
||||||
|
statsFiles = nil
|
||||||
|
|
||||||
// 按修改时间排序文件(从新到旧)
|
// 按修改时间排序文件(从新到旧)
|
||||||
sort.Slice(filesWithInfo, func(i, j int) bool {
|
sort.Slice(filesWithInfo, func(i, j int) bool {
|
||||||
return filesWithInfo[i].modTime.After(filesWithInfo[j].modTime)
|
return filesWithInfo[i].modTime.After(filesWithInfo[j].modTime)
|
||||||
@ -468,6 +492,10 @@ func (c *Collector) cleanupOldMetricsFiles() error {
|
|||||||
log.Printf("[Metrics] Removed old metrics file: %s", filesWithInfo[i].fullPath)
|
log.Printf("[Metrics] Removed old metrics file: %s", filesWithInfo[i].fullPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 释放filesWithInfo内存
|
||||||
|
filesWithInfo = nil
|
||||||
|
runtime.GC()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +595,10 @@ func (c *Collector) validateLoadedData() error {
|
|||||||
// 验证路径统计
|
// 验证路径统计
|
||||||
var totalPathRequests int64
|
var totalPathRequests int64
|
||||||
c.pathStats.Range(func(_, value interface{}) bool {
|
c.pathStats.Range(func(_, value interface{}) bool {
|
||||||
stats := value.(models.PathStats)
|
stats, ok := value.(*models.PathStats)
|
||||||
|
if !ok {
|
||||||
|
return true
|
||||||
|
}
|
||||||
requestCount := stats.Requests.Load()
|
requestCount := stats.Requests.Load()
|
||||||
errorCount := stats.Errors.Load()
|
errorCount := stats.Errors.Load()
|
||||||
if requestCount < 0 || errorCount < 0 {
|
if requestCount < 0 || errorCount < 0 {
|
||||||
@ -688,10 +719,16 @@ func (c *Collector) startMetricsSaver() {
|
|||||||
ticker := time.NewTicker(saveInterval)
|
ticker := time.NewTicker(saveInterval)
|
||||||
go func() {
|
go func() {
|
||||||
for range ticker.C {
|
for range ticker.C {
|
||||||
|
func() {
|
||||||
|
// 使用匿名函数来确保每次迭代后都能释放内存
|
||||||
stats := c.GetStats()
|
stats := c.GetStats()
|
||||||
if err := c.SaveMetrics(stats); err != nil {
|
if err := c.SaveMetrics(stats); err != nil {
|
||||||
log.Printf("[Metrics] Failed to save metrics: %v", err)
|
log.Printf("[Metrics] Failed to save metrics: %v", err)
|
||||||
}
|
}
|
||||||
|
// 释放内存
|
||||||
|
stats = nil
|
||||||
|
runtime.GC()
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user