高性能 Go 语言带 TTL 的内存缓存实现:精确过期、自动刷新、并发安全
在高并发服务开发中,内存缓存是提升性能的关键组件。而支持自动过期(TTL) 的缓存更是常见需求。本文将介绍一种基于 Go 语言实现的高性能、并发安全、支持过期时间自动刷新的内存缓存方案,并附完整源码、测试用例及性能分析。
🎯 设计目标
- 所有条目使用统一的全局 TTL(Time-To-Live)
- Set(key, value) 会重置该 key 的过期时间
- 过期后自动删除,无需手动清理
- 并发安全:支持多 goroutine 同时读写
- 高性能:读操作零分配,写操作开销可控
- 精确过期:避免"提前误删"或"延迟删除"
🧠 核心思路:为每个 Key 绑定独立 Timer
传统方案常使用后台协程轮询 + 堆(heap)管理过期时间,但存在两个问题:
- 同一个 key 多次 Set 会导致堆中冗余项;
- 旧的过期计划可能误删刚被刷新的 key。
我们采用更简洁、精确的方案:
每次 Set 时,为该 key 启动一个 time.Timer,在 TTL 后自动删除。若 key 被再次 Set,则取消旧 Timer,启动新 Timer。
Go 的 time.Timer 由 runtime 高效管理,轻量且精确,非常适合此场景。
📦 完整源码 (cache.go)
// cache.go
package timecacheimport ("sync""time"
)// Cache is a thread-safe in-memory cache with fixed TTL.
type Cache[T any] struct {items map[string]Ttimers map[string]*time.Timermu sync.RWMutexttl time.Duration
}// NewCache creates a new cache with the given TTL.
// Panics if ttl <= 0.
func NewCache[T any](ttl time.Duration) *Cache[T] {if ttl <= 0 {panic("TTL must be positive")}return &Cache[T]{items: make(map[string]T),timers: make(map[string]*time.Timer),ttl: ttl,}
}// Set stores a value and resets its expiration timer.
func (c *Cache[T]) Set(key string, value T) {c.mu.Lock()defer c.mu.Unlock()// Cancel existing timer if anyif timer, exists := c.timers[key]; exists {timer.Stop()delete(c.timers, key)}// Store valuec.items[key] = value// Schedule expirationtimer := time.AfterFunc(c.ttl, func() {c.mu.Lock()defer c.mu.Unlock()// Double-check existence to avoid raceif _, exists := c.items[key]; exists {delete(c.items, key)// timers[key] already deleted above, but safe to double-delete}})c.timers[key] = timer
}// Get returns the value if it exists and has not expired.
func (c *Cache[T]) Get(key string) (T, bool) {c.mu.RLock()defer c.mu.RUnlock()if val, ok := c.items[key]; ok {return val, true}var zero Treturn zero, false
}// Delete removes a key immediately and cancels its timer.