Skip to content

Commit d57b507

Browse files
committed
fix(metrics): 修复缓存命中率和节省字节数的统计问题
将 RecordRequest 替换为 RecordRequestWithCache 以正确记录缓存命中/未命中状态,并统计节省的字节数。修复了缓存命中率始终为0的问题,同时支持304响应作为缓存命中场景。
1 parent b9f968b commit d57b507

File tree

3 files changed

+122
-10
lines changed

3 files changed

+122
-10
lines changed

FIX_CACHE_HIT_RATE.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# 修复缓存命中率统计问题
2+
3+
## 问题描述
4+
5+
路径映射的缓存命中率始终显示为 0,即使缓存系统正常工作。
6+
7+
## 根本原因
8+
9+
在记录请求统计时,所有的请求都使用了普通的 `RecordRequest()` 方法,而不是 `RecordRequestWithCache()` 方法。这导致:
10+
11+
1. `CacheHits``CacheMisses` 计数器从未被更新
12+
2. 缓存命中率计算公式 `cacheHitRate = cacheHits / (cacheHits + cacheMisses)` 始终返回 0(因为分子分母都是0)
13+
3. `BytesSaved`(节省的字节数)统计也始终为0
14+
15+
## 修复方案
16+
17+
将所有的请求记录从 `RecordRequest()` 改为 `RecordRequestWithCache()`,并传递正确的缓存状态:
18+
19+
### 1. 缓存命中场景(3处修改)
20+
21+
**文件**: `internal/handler/proxy.go``internal/handler/mirror_proxy.go`
22+
23+
**修改前**:
24+
```go
25+
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(start), item.Size, iputil.GetClientIP(r), r)
26+
```
27+
28+
**修改后**:
29+
```go
30+
// 缓存命中,节省的字节数等于文件大小
31+
collector.RecordRequestWithCache(r.URL.Path, http.StatusOK, time.Since(start), item.Size, iputil.GetClientIP(r), r, true, item.Size)
32+
```
33+
34+
**修改位置**:
35+
- `internal/handler/proxy.go:369` - handleCacheHit 方法
36+
- `internal/handler/proxy.go:364` - handleCacheHit 方法 (304 Not Modified)
37+
- `internal/handler/mirror_proxy.go:186` - handleCacheHit 方法
38+
- `internal/handler/mirror_proxy.go:180` - handleCacheHit 方法 (304 Not Modified)
39+
40+
### 2. 缓存未命中场景(3处修改)
41+
42+
**文件**: `internal/handler/proxy.go``internal/handler/mirror_proxy.go`
43+
44+
**修改前**:
45+
```go
46+
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r)
47+
```
48+
49+
**修改后**:
50+
```go
51+
// 缓存未命中
52+
collector.RecordRequestWithCache(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r, false, 0)
53+
```
54+
55+
**修改位置**:
56+
- `internal/handler/proxy.go:328` - ServeHTTP 主流程
57+
- `internal/handler/proxy.go:422` - handleMissedCache 方法
58+
- `internal/handler/mirror_proxy.go:150` - ServeHTTP 主流程
59+
60+
## 缓存统计逻辑
61+
62+
统计数据在 `internal/metrics/collector.go:826-832` 中更新:
63+
64+
```go
65+
// 更新缓存统计
66+
if m.CacheHit {
67+
pathMetrics.CacheHits.Add(1)
68+
pathMetrics.BytesSaved.Add(m.BytesSaved)
69+
} else {
70+
pathMetrics.CacheMisses.Add(1)
71+
}
72+
```
73+
74+
缓存命中率在 `internal/models/metrics.go:100-106` 中计算:
75+
76+
```go
77+
cacheHits := p.CacheHits.Load()
78+
cacheMisses := p.CacheMisses.Load()
79+
totalCache := cacheHits + cacheMisses
80+
var cacheHitRate float64
81+
if totalCache > 0 {
82+
cacheHitRate = float64(cacheHits) / float64(totalCache)
83+
}
84+
```
85+
86+
## 测试验证
87+
88+
修复后,需要验证:
89+
90+
1. **缓存命中时**: `cache_hit_rate` 应该增加
91+
2. **缓存未命中时**: 请求仍然被正确记录
92+
3. **混合场景**: 命中率应该准确反映实际的缓存效率(例如 10次请求中7次命中 = 70%)
93+
4. **节省字节数**: `bytes_saved` 应该累计所有缓存命中节省的带宽
94+
95+
## 影响范围
96+
97+
- ✅ 修复了路径级别的缓存命中率统计
98+
- ✅ 修复了缓存节省字节数的统计
99+
- ✅ 同时适用于 Proxy 和 Mirror 两种代理模式
100+
- ✅ 不影响其他统计指标(请求数、错误数、延迟等)
101+
102+
## 注意事项
103+
104+
- 304 Not Modified 响应也计入缓存命中,因为它确实节省了带宽传输
105+
- `bytesSaved` 在304响应时设为 `item.Size`,因为客户端没有下载文件内容
106+
- 历史统计数据可能仍为0(因为旧数据没有记录缓存状态),新请求才会正确统计

internal/handler/mirror_proxy.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,8 @@ func (h *MirrorProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
146146
// 记录访问日志
147147
log.Printf(h.mirrorService.CreateLogEntry(mirrorReq, resp.StatusCode, time.Since(startTime), written))
148148

149-
// 记录统计信息
150-
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(startTime), written, iputil.GetClientIP(r), r)
149+
// 记录统计信息(缓存未命中)
150+
collector.RecordRequestWithCache(r.URL.Path, resp.StatusCode, time.Since(startTime), written, iputil.GetClientIP(r), r, false, 0)
151151
}
152152

153153
// handleCORSPreflight 处理CORS预检请求
@@ -173,12 +173,15 @@ func (h *MirrorProxyHandler) handleCacheHit(w http.ResponseWriter, r *http.Reque
173173
w.Header().Set("Content-Encoding", item.ContentEncoding)
174174
}
175175
w.Header().Set("Proxy-Go-Cache-HIT", "1")
176-
176+
177177
if notModified {
178178
w.WriteHeader(http.StatusNotModified)
179+
// 记录缓存命中(304响应也算命中,节省了带宽)
180+
collector.RecordRequestWithCache(r.URL.Path, http.StatusNotModified, time.Since(startTime), 0, iputil.GetClientIP(r), r, true, item.Size)
179181
return
180182
}
181-
183+
182184
http.ServeFile(w, r, item.FilePath)
183-
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(startTime), item.Size, iputil.GetClientIP(r), r)
185+
// 记录缓存命中,节省的字节数等于文件大小
186+
collector.RecordRequestWithCache(r.URL.Path, http.StatusOK, time.Since(startTime), item.Size, iputil.GetClientIP(r), r, true, item.Size)
184187
}

internal/handler/proxy.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,8 @@ func (h *ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
324324
return
325325
}
326326

327-
// 记录统计信息
328-
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r)
327+
// 记录统计信息(缓存未命中)
328+
collector.RecordRequestWithCache(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r, false, 0)
329329
}
330330

331331
// handleWelcome 处理根路径欢迎消息
@@ -360,10 +360,13 @@ func (h *ProxyHandler) handleCacheHit(w http.ResponseWriter, r *http.Request, it
360360

361361
if notModified {
362362
w.WriteHeader(http.StatusNotModified)
363+
// 记录缓存命中(304响应也算命中,节省了带宽)
364+
collector.RecordRequestWithCache(r.URL.Path, http.StatusNotModified, time.Since(start), 0, iputil.GetClientIP(r), r, true, item.Size)
363365
return
364366
}
365367
http.ServeFile(w, r, item.FilePath)
366-
collector.RecordRequest(r.URL.Path, http.StatusOK, time.Since(start), item.Size, iputil.GetClientIP(r), r)
368+
// 记录缓存命中,节省的字节数等于文件大小
369+
collector.RecordRequestWithCache(r.URL.Path, http.StatusOK, time.Since(start), item.Size, iputil.GetClientIP(r), r, true, item.Size)
367370
}
368371

369372
// handleMissedCache 处理缓存未命中或缓存失效的情况,重新执行代理请求
@@ -415,6 +418,6 @@ func (h *ProxyHandler) handleMissedCache(w http.ResponseWriter, r *http.Request,
415418
return
416419
}
417420

418-
// 记录统计信息
419-
collector.RecordRequest(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r)
421+
// 记录统计信息(缓存未命中)
422+
collector.RecordRequestWithCache(r.URL.Path, resp.StatusCode, time.Since(start), written, iputil.GetClientIP(r), r, false, 0)
420423
}

0 commit comments

Comments
 (0)