Go (Golang) 中的缓存:Redis、内存缓存及其他解决方案
缓存是提高 Go 应用程序性能并减轻数据库负载的关键策略之一。在本文中,我们将探讨实现缓存的主要方法和库:从简单的内存解决方案到基于 Redis 的分布式缓存。您将了解何时选择哪种工具,以及如何在 Go 项目中正确组织缓存。
1. 内置功能:map 和 sync.Map
在 Go 中最简单的缓存方式是使用带有互斥锁的普通 map 或线程安全的 sync.Map。这些方法适用于不需要复杂失效策略的小型项目或原型。
sync.Map 示例:
package main
import ( "fmt" "sync")
type Cache struct { data sync.Map}
func (c *Cache) Set(key string, value interface{}) { c.data.Store(key, value)}
func (c *Cache) Get(key string) (interface{}, bool) { return c.data.Load(key)}
func main() { cache := &Cache{} cache.Set("user:1", "Alice") if val, ok := cache.Get("user:1"); ok { fmt.Println("Found:", val) }}优点:简单,零依赖。
缺点:没有 TTL,没有自动清理,内存不受限制。
2. 带 TTL 的内存缓存:freecache
Freecache 是一个快速的内存缓存库,支持 TTL(生存时间)。它采用分段架构以最小化锁竞争,并高效管理内存。
安装:
go get github.com/coocood/freecache使用示例:
package main
import ( "fmt" "github.com/coocood/freecache")
func main() { // 创建一个 100 MB 的缓存 cache := freecache.NewCache(100 * 1024 * 1024)
// 设置一个 TTL 为 10 秒的值 cache.Set([]byte("mykey"), []byte("myvalue"), 10)
// 获取值 if val, err := cache.Get([]byte("mykey")); err == nil { fmt.Println("Value:", string(val)) } else { fmt.Println("Key not found or expired") }}优点:自动按 TTL 清理,CPU 占用低,支持大数据量。
缺点:仅适用于单个进程(非分布式)。
3. BigCache — freecache 的替代方案
BigCache 是另一个流行的内存缓存库,针对存储大量条目(数百万)进行了优化,访问时间极短。它也支持 TTL 和自动淘汰旧数据。
示例:
package main
import ( "fmt" "github.com/allegro/bigcache/v3" "time")
func main() { config := bigcache.Config{ Shards: 1024, LifeWindow: 10 * time.Minute, CleanWindow: 5 * time.Minute, MaxEntriesInWindow: 1000 * 10 * 60, MaxEntrySize: 500, Verbose: true, }
cache, _ := bigcache.NewBigCache(config) cache.Set("mykey", []byte("bigcache value")) val, _ := cache.Get("mykey") fmt.Println(string(val))}优点:在大量键的情况下性能高,配置灵活。
缺点:与 freecache 一样,是本地缓存。
4. 使用 Redis 和 go-redis 进行分布式缓存
对于分布式系统,当多个应用程序实例需要共享一个缓存时,使用 Redis。Go 最流行的客户端是 go-redis(以前是 go-redis/redis)。
安装:
go get github.com/redis/go-redis/v9