Update metrics tracking and enhance cache eviction strategies
Release Tag / release (push) Successful in 34s
Release Tag / release (push) Successful in 34s
- Added metrics for bytes saved from cache to improve performance insights. - Updated cache eviction strategies in MemoryFS and DiskFS to include metrics tracking for hits and evictions. - Enhanced README.md with updated garbage collection algorithm descriptions and recommendations for cache usage. - Introduced new madviseSequential functionality for improved memory access hints on Unix systems. - Adjusted validation configuration in examples to better reflect realistic usage scenarios.
This commit is contained in:
@@ -110,6 +110,7 @@ func (sc *SteamCache) handleCacheHit(w http.ResponseWriter, r *http.Request, cac
|
||||
sc.metrics.IncrementCacheHits()
|
||||
sc.metrics.AddResponseTime(time.Since(tstart))
|
||||
sc.metrics.AddBytesServed(int64(len(cachedData)))
|
||||
sc.metrics.AddBytesSaved(int64(len(cachedData)))
|
||||
sc.metrics.IncrementServiceRequests(service.Name)
|
||||
|
||||
logger.Logger.Debug().
|
||||
@@ -197,6 +198,7 @@ func (sc *SteamCache) waitForCoalesced(w http.ResponseWriter, r *http.Request, c
|
||||
sc.metrics.IncrementCacheCoalesced()
|
||||
sc.metrics.AddResponseTime(time.Since(tstart))
|
||||
sc.metrics.AddBytesServed(int64(len(responseData)))
|
||||
sc.metrics.AddBytesSaved(int64(len(responseData)))
|
||||
sc.metrics.IncrementServiceRequests(service.Name)
|
||||
|
||||
logger.Logger.Info().
|
||||
@@ -233,9 +235,6 @@ func (sc *SteamCache) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
defer sc.requestSemaphore.Release(1)
|
||||
|
||||
// Track total requests
|
||||
sc.metrics.IncrementTotalRequests()
|
||||
|
||||
// Apply per-client rate limiting
|
||||
clientLimiter := sc.getOrCreateClientLimiter(clientIP)
|
||||
|
||||
@@ -305,6 +304,11 @@ func (sc *SteamCache) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
Str("client_ip", clientIP).
|
||||
Msg("Generated cache key")
|
||||
|
||||
// Only count real cacheable service traffic toward total_requests / hit_rate.
|
||||
// Special endpoints (/, /metrics, /lancache-heartbeat) and unsupported services
|
||||
// are intentionally excluded so that idle monitoring doesn't dilute the hit rate.
|
||||
sc.metrics.IncrementTotalRequests()
|
||||
|
||||
if sc.handleCacheHit(w, r, cachePath, cacheKey, urlPath, service, clientIP, tstart) {
|
||||
return
|
||||
}
|
||||
@@ -588,8 +592,6 @@ func (sc *SteamCache) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
sc.metrics.IncrementServiceError("cache_write")
|
||||
_ = sc.vfs.Delete(cachePath) // best-effort removal of partial corrupt cache entry on write failure; non-fatal. Deferred cacheWriter.Close() (from earlier in block) runs after this on error unwind path (harmless per DiskFS design)
|
||||
} else {
|
||||
// Track successful cache write
|
||||
sc.metrics.AddBytesCached(int64(len(cacheData)))
|
||||
logger.Logger.Debug().
|
||||
Str("key", cacheKey).
|
||||
Str("url", urlPath).
|
||||
|
||||
@@ -22,7 +22,9 @@ type Metrics struct {
|
||||
// Performance metrics
|
||||
TotalResponseTime int64 // in nanoseconds
|
||||
TotalBytesServed int64
|
||||
TotalBytesCached int64
|
||||
TotalBytesSaved int64 // bytes served from cache instead of being re-downloaded from upstream
|
||||
|
||||
|
||||
|
||||
// Cache metrics
|
||||
MemoryCacheSize int64
|
||||
@@ -98,9 +100,10 @@ func (m *Metrics) AddBytesServed(bytes int64) {
|
||||
atomic.AddInt64(&m.TotalBytesServed, bytes)
|
||||
}
|
||||
|
||||
// AddBytesCached adds bytes cached to the total
|
||||
func (m *Metrics) AddBytesCached(bytes int64) {
|
||||
atomic.AddInt64(&m.TotalBytesCached, bytes)
|
||||
// AddBytesSaved records bytes that were served from the cache instead of being
|
||||
// fetched again from the upstream (the main value metric for a cache).
|
||||
func (m *Metrics) AddBytesSaved(bytes int64) {
|
||||
atomic.AddInt64(&m.TotalBytesSaved, bytes)
|
||||
}
|
||||
|
||||
// SetMemoryCacheSize sets the current memory cache size
|
||||
@@ -191,8 +194,8 @@ func (m *Metrics) GetStats() *Stats {
|
||||
RateLimited: atomic.LoadInt64(&m.RateLimited),
|
||||
HitRate: hitRate,
|
||||
AvgResponseTime: avgResponseTime,
|
||||
TotalBytesServed: atomic.LoadInt64(&m.TotalBytesServed),
|
||||
TotalBytesCached: atomic.LoadInt64(&m.TotalBytesCached),
|
||||
TotalBytesServed: atomic.LoadInt64(&m.TotalBytesServed),
|
||||
TotalBytesSaved: atomic.LoadInt64(&m.TotalBytesSaved),
|
||||
MemoryCacheSize: atomic.LoadInt64(&m.MemoryCacheSize),
|
||||
DiskCacheSize: atomic.LoadInt64(&m.DiskCacheSize),
|
||||
MemoryCacheHits: atomic.LoadInt64(&m.MemoryCacheHits),
|
||||
@@ -218,7 +221,7 @@ func (m *Metrics) Reset() {
|
||||
atomic.StoreInt64(&m.RateLimited, 0)
|
||||
atomic.StoreInt64(&m.TotalResponseTime, 0)
|
||||
atomic.StoreInt64(&m.TotalBytesServed, 0)
|
||||
atomic.StoreInt64(&m.TotalBytesCached, 0)
|
||||
atomic.StoreInt64(&m.TotalBytesSaved, 0)
|
||||
atomic.StoreInt64(&m.MemoryCacheHits, 0)
|
||||
atomic.StoreInt64(&m.DiskCacheHits, 0)
|
||||
atomic.StoreInt64(&m.Promotions, 0)
|
||||
@@ -247,9 +250,11 @@ type Stats struct {
|
||||
RateLimited int64
|
||||
HitRate float64
|
||||
AvgResponseTime time.Duration
|
||||
TotalBytesServed int64
|
||||
TotalBytesCached int64
|
||||
MemoryCacheSize int64
|
||||
TotalBytesServed int64
|
||||
TotalBytesSaved int64
|
||||
MemoryCacheSize int64
|
||||
|
||||
|
||||
DiskCacheSize int64
|
||||
MemoryCacheHits int64
|
||||
DiskCacheHits int64
|
||||
@@ -291,7 +296,8 @@ func WriteText(w http.ResponseWriter, stats *Stats) {
|
||||
_, _ = fmt.Fprintf(w, "hit_rate %.4f\n", stats.HitRate)
|
||||
_, _ = fmt.Fprintf(w, "avg_response_time_ms %.2f\n", float64(stats.AvgResponseTime.Nanoseconds())/1e6)
|
||||
_, _ = fmt.Fprintf(w, "total_bytes_served %d\n", stats.TotalBytesServed)
|
||||
_, _ = fmt.Fprintf(w, "total_bytes_cached %d\n", stats.TotalBytesCached)
|
||||
_, _ = fmt.Fprintf(w, "total_bytes_saved %d\n", stats.TotalBytesSaved)
|
||||
|
||||
_, _ = fmt.Fprintf(w, "memory_cache_size %d\n", stats.MemoryCacheSize)
|
||||
_, _ = fmt.Fprintf(w, "disk_cache_size %d\n", stats.DiskCacheSize)
|
||||
_, _ = fmt.Fprintf(w, "uptime_seconds %.2f\n", stats.Uptime.Seconds())
|
||||
|
||||
@@ -179,6 +179,17 @@ func New(address string, memorySize string, diskSize string, diskPath, upstream,
|
||||
metrics: metrics.NewMetrics(),
|
||||
}
|
||||
|
||||
// Wire metrics into TieredCache so promotions are counted.
|
||||
c.SetMetrics(sc.metrics)
|
||||
|
||||
// Wire metrics into the concrete storage tiers (MemoryFS / DiskFS) so per-tier hits and evictions are counted.
|
||||
if m != nil {
|
||||
m.SetMetrics(sc.metrics)
|
||||
}
|
||||
if d != nil {
|
||||
d.SetMetrics(sc.metrics)
|
||||
}
|
||||
|
||||
// Wire the request processor (constructor injection of interfaces for the owned wrappers + vfs + client + scalars).
|
||||
// Done after all fields including wrappers are set; before attach goroutines (no impact on lifecycle paths).
|
||||
sc.processor = newRequestProcessor(sc)
|
||||
@@ -209,12 +220,16 @@ func New(address string, memorySize string, diskSize string, diskPath, upstream,
|
||||
sc.wg.Add(1)
|
||||
go func() {
|
||||
defer sc.wg.Done()
|
||||
t0 := time.Now()
|
||||
_ = d.Size()
|
||||
select {
|
||||
case <-sc.shutdownCh:
|
||||
return
|
||||
default:
|
||||
c.SetSlow(dgc)
|
||||
logger.Logger.Info().
|
||||
Dur("attach_delay", time.Since(t0)).
|
||||
Msg("Disk slow tier attached (mixed mode); prior traffic was memory-only")
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user