From 095b087fd8050cfaa98bc628126e47b03394f204 Mon Sep 17 00:00:00 2001 From: wood chen Date: Sun, 9 Mar 2025 10:35:00 +0800 Subject: [PATCH] =?UTF-8?q?refactor(metrics):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=8C=87=E6=A0=87=E6=94=B6=E9=9B=86=E5=92=8C=E5=86=85=E5=AD=98?= =?UTF-8?q?=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修改路径统计数据结构为指针类型,提高性能 - 使用原子操作方法替换旧的原子操作 - 添加内存释放和垃圾回收机制 - 限制路径统计数量,只保留前20个路径 - 优化指标保存和文件清理逻辑,减少内存使用 --- internal/metrics/collector.go | 65 +++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/internal/metrics/collector.go b/internal/metrics/collector.go index dfe6b4b..0f16f14 100644 --- a/internal/metrics/collector.go +++ b/internal/metrics/collector.go @@ -165,15 +165,17 @@ func (c *Collector) RecordRequest(path string, status int, latency time.Duration // 更新路径统计 c.pathStatsMutex.Lock() if value, ok := c.pathStats.Load(path); ok { - stat := value.(models.PathStats) - stat.Requests.Store(stat.Requests.Load() + 1) - stat.Bytes.Store(stat.Bytes.Load() + bytes) - stat.LatencySum.Store(stat.LatencySum.Load() + int64(latency)) - if status >= 400 { - stat.Errors.Store(stat.Errors.Load() + 1) + stat, ok := value.(*models.PathStats) + if ok { + stat.Requests.Add(1) + stat.Bytes.Add(bytes) + stat.LatencySum.Add(int64(latency)) + if status >= 400 { + stat.Errors.Add(1) + } } } else { - newStat := models.PathStats{ + newStat := &models.PathStats{ Requests: atomic.Int64{}, Bytes: atomic.Int64{}, LatencySum: atomic.Int64{}, @@ -262,7 +264,10 @@ func (c *Collector) GetStats() map[string]interface{} { pathStatsMap := make(map[string]interface{}) c.pathStats.Range(func(key, value interface{}) bool { path := key.(string) - stats := value.(models.PathStats) + stats, ok := value.(*models.PathStats) + if !ok { + return true + } requestCount := stats.Requests.Load() if requestCount > 0 { latencySum := stats.LatencySum.Load() @@ -289,7 +294,11 @@ func (c *Collector) GetStats() map[string]interface{} { AvgLatency string } + // 限制路径统计的数量,只保留前N个 + maxPaths := 20 // 只保留前20个路径 var pathStatsList []pathStat + + // 先将pathStatsMap转换为pathStatsList for path, statData := range pathStatsMap { if stat, ok := statData.(map[string]interface{}); ok { 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 { 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 }) + // 只保留前maxPaths个 + if len(pathStatsList) > maxPaths { + pathStatsList = pathStatsList[:maxPaths] + } + // 转换为有序的map orderedPathStats := make([]map[string]interface{}, len(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 { 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) } + // 释放内存 + data = nil + runtime.GC() + c.lastSaveTime = time.Now() log.Printf("[Metrics] Saved metrics to %s", filename) return nil @@ -455,6 +476,9 @@ func (c *Collector) cleanupOldMetricsFiles() error { }) } + // 释放statsFiles内存 + statsFiles = nil + // 按修改时间排序文件(从新到旧) sort.Slice(filesWithInfo, func(i, j int) bool { 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) } + // 释放filesWithInfo内存 + filesWithInfo = nil + runtime.GC() + return nil } @@ -567,7 +595,10 @@ func (c *Collector) validateLoadedData() error { // 验证路径统计 var totalPathRequests int64 c.pathStats.Range(func(_, value interface{}) bool { - stats := value.(models.PathStats) + stats, ok := value.(*models.PathStats) + if !ok { + return true + } requestCount := stats.Requests.Load() errorCount := stats.Errors.Load() if requestCount < 0 || errorCount < 0 { @@ -688,10 +719,16 @@ func (c *Collector) startMetricsSaver() { ticker := time.NewTicker(saveInterval) go func() { for range ticker.C { - stats := c.GetStats() - if err := c.SaveMetrics(stats); err != nil { - log.Printf("[Metrics] Failed to save metrics: %v", err) - } + func() { + // 使用匿名函数来确保每次迭代后都能释放内存 + stats := c.GetStats() + if err := c.SaveMetrics(stats); err != nil { + log.Printf("[Metrics] Failed to save metrics: %v", err) + } + // 释放内存 + stats = nil + runtime.GC() + }() } }()