Golang内存缓存实现与优化指南

Golang内存缓存实现与优化指南 我正在尝试实现内存缓存。有哪些可能的方法可以实现它?有哪些最佳的三方包可用,或者使用内置功能来构建它是否更可取? 我还有一个疑问,memcache 和内存缓存是相同的还是完全不同的?

2 回复

pkg.go.dev

sync package - sync - Go Packages

sync 包提供了基本的同步原语,例如互斥锁。


GitHub - Karl1b/cachetest

GitHub - Karl1b/cachetest

通过在 GitHub 上创建一个帐户来为 Karl1b/cachetest 开发做出贡献。

更多关于Golang内存缓存实现与优化指南的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现内存缓存有多种方式,以下是几种主要方法:

1. 使用内置的sync.Map(适用于读多写少场景)

package main

import (
    "sync"
    "time"
)

type CacheItem struct {
    Value      interface{}
    Expiration int64
}

type MemoryCache struct {
    items sync.Map
    mu    sync.RWMutex
}

func NewMemoryCache() *MemoryCache {
    return &MemoryCache{}
}

func (c *MemoryCache) Set(key string, value interface{}, ttl time.Duration) {
    expiration := time.Now().Add(ttl).UnixNano()
    c.items.Store(key, CacheItem{
        Value:      value,
        Expiration: expiration,
    })
}

func (c *MemoryCache) Get(key string) (interface{}, bool) {
    item, found := c.items.Load(key)
    if !found {
        return nil, false
    }
    
    cacheItem := item.(CacheItem)
    if time.Now().UnixNano() > cacheItem.Expiration {
        c.items.Delete(key)
        return nil, false
    }
    
    return cacheItem.Value, true
}

2. 使用map + sync.RWMutex(更精细的控制)

type RWCache struct {
    items map[string]CacheItem
    mu    sync.RWMutex
}

func NewRWCache() *RWCache {
    return &RWCache{
        items: make(map[string]CacheItem),
    }
}

func (c *RWCache) Set(key string, value interface{}, ttl time.Duration) {
    c.mu.Lock()
    defer c.mu.Unlock()
    
    c.items[key] = CacheItem{
        Value:      value,
        Expiration: time.Now().Add(ttl).UnixNano(),
    }
}

func (c *RWCache) Get(key string) (interface{}, bool) {
    c.mu.RLock()
    item, found := c.items[key]
    c.mu.RUnlock()
    
    if !found {
        return nil, false
    }
    
    if time.Now().UnixNano() > item.Expiration {
        c.mu.Lock()
        delete(c.items, key)
        c.mu.Unlock()
        return nil, false
    }
    
    return item.Value, true
}

3. 流行的第三方包

go-cache(最常用)

import (
    "github.com/patrickmn/go-cache"
    "time"
)

func main() {
    // 创建缓存,默认过期时间5分钟,清理间隔10分钟
    c := cache.New(5*time.Minute, 10*time.Minute)
    
    // 设置缓存
    c.Set("key", "value", cache.DefaultExpiration)
    
    // 获取缓存
    if x, found := c.Get("key"); found {
        fmt.Println(x)
    }
    
    // 带过期时间的设置
    c.Set("foo", "bar", 30*time.Second)
}

bigcache(高性能,适用于大量数据)

import "github.com/allegro/bigcache"

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("key", []byte("value"))
    
    entry, _ := cache.Get("key")
    fmt.Println(string(entry))
}

ristretto(高性能,高命中率)

import "github.com/dgraph-io/ristretto"

func main() {
    cache, _ := ristretto.NewCache(&ristretto.Config{
        NumCounters: 1e7,     // 键跟踪数量
        MaxCost:     1 << 30, // 最大成本(字节)
        BufferItems: 64,      // 缓冲区大小
    })
    
    cache.Set("key", "value", 1)
    cache.Wait()
    
    if value, found := cache.Get("key"); found {
        fmt.Println(value)
    }
}

4. 关于memcache与内存缓存的区别

memcache(通常指Memcached)和内存缓存是不同的:

内存缓存(In-memory Cache)

  • 应用程序进程内的缓存
  • 零网络延迟
  • 数据与应用程序生命周期相同(重启丢失)
  • 示例:go-cache, bigcache, ristretto

Memcached

  • 独立的内存缓存服务器
  • 需要网络访问
  • 分布式支持
  • 数据持久于独立服务
  • Go客户端:github.com/bradfitz/gomemcache
// Memcached使用示例
import "github.com/bradfitz/gomemcache/memcache"

func main() {
    mc := memcache.New("localhost:11211")
    mc.Set(&memcache.Item{Key: "key", Value: []byte("value")})
    
    item, _ := mc.Get("key")
    fmt.Println(string(item.Value))
}

5. 性能优化建议

// 使用字节切片而非接口{}减少分配
type ByteCache struct {
    items map[string][]byte
    mu    sync.RWMutex
}

// 批量操作减少锁竞争
func (c *ByteCache) MultiSet(items map[string][]byte) {
    c.mu.Lock()
    defer c.mu.Unlock()
    
    for k, v := range items {
        c.items[k] = v
    }
}

// 使用对象池重用对象
var itemPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 0, 1024)
    },
}

选择方案:

  • 简单场景:go-cache
  • 高性能需求:ristretto或bigcache
  • 分布式需求:Memcached或Redis
  • 最小依赖:内置sync.Map或map+mutex
回到顶部