Golang支持TTL的本地缓存实现
在Golang中如何实现支持TTL的本地缓存?希望能找到一个轻量级的解决方案,最好不需要依赖外部存储。具体需求是:
- 支持设置键值对的过期时间
- 能够自动清理过期的缓存项
- 线程安全
- 性能较好
有没有推荐的标准库或第三方库可以直接使用?或者需要自己实现的话,有什么需要注意的关键点?
2 回复
在Go语言中,实现支持TTL(生存时间)的本地缓存可以通过标准库的sync.Map结合自定义结构体和goroutine来完成。以下是一个简单高效的实现示例:
package main
import (
"sync"
"time"
)
type item struct {
value interface{}
expiration int64
}
type Cache struct {
items *sync.Map
stop chan struct{}
}
func NewCache(cleanupInterval time.Duration) *Cache {
c := &Cache{
items: &sync.Map{},
stop: make(chan struct{}),
}
// 启动定期清理过期键的goroutine
go func() {
ticker := time.NewTicker(cleanupInterval)
defer ticker.Stop()
for {
select {
case <-ticker.C:
now := time.Now().UnixNano()
c.items.Range(func(key, value interface{}) bool {
if item := value.(*item); item.expiration > 0 && now > item.expiration {
c.items.Delete(key)
}
return true
})
case <-c.stop:
return
}
}
}()
return c
}
// Set 存储键值对,并设置TTL
func (c *Cache) Set(key, value interface{}, ttl time.Duration) {
var exp int64
if ttl > 0 {
exp = time.Now().Add(ttl).UnixNano()
}
c.items.Store(key, &item{
value: value,
expiration: exp,
})
}
// Get 获取键对应的值,如果过期或不存在返回nil
func (c *Cache) Get(key interface{}) interface{} {
val, ok := c.items.Load(key)
if !ok {
return nil
}
item := val.(*item)
if item.expiration > 0 && time.Now().UnixNano() > item.expiration {
c.items.Delete(key)
return nil
}
return item.value
}
// Delete 删除指定键
func (c *Cache) Delete(key interface{}) {
c.items.Delete(key)
}
// Close 停止缓存清理goroutine
func (c *Cache) Close() {
close(c.stop)
}
使用示例:
func main() {
cache := NewCache(time.Minute) // 每分钟清理一次过期键
// 设置缓存,TTL为5秒
cache.Set("key1", "value1", 5*time.Second)
// 立即获取
if val := cache.Get("key1"); val != nil {
println(val.(string)) // 输出: value1
}
// 6秒后获取(已过期)
time.Sleep(6 * time.Second)
if val := cache.Get("key1"); val == nil {
println("key1已过期") // 输出: key1已过期
}
cache.Close()
}
主要特性:
- 使用
sync.Map保证并发安全 - 后台goroutine定期清理过期数据
- 获取时进行过期检查(惰性删除)
- 支持无TTL永久存储(设置ttl=0)
注意事项:
- 适用于单机应用,分布式环境需改用Redis等方案
- 定期清理间隔需根据业务需求调整
- 大量数据时注意内存占用
如需更完整功能(如统计、事件回调等),建议使用成熟的第三方库如github.com/patrickmn/go-cache。


