[每周一更]-(第146期):BigCache使用指南:打造高并发无GC压力的本地缓存

[每周一更]-(第146期):BigCache使用指南:打造高并发无GC压力的本地缓存_第1张图片

bigcache 是 Go 中一个高性能的本地内存缓存库,专为 大数据量、高并发场景下的缓存需求设计,避免 GC 开销、极致性能优化。适合用于需要快速访问、低延迟、本地缓存的数据。


一句话理解

bigcache 是比 map[string]interface{} 更适合做 大量键值对、高并发访问场景的本地缓存。


适用场景

适用场景 描述
大量缓存键值(数十万级以上) 内存分片+避免 GC 停顿
高并发读写缓存 支持每秒上百万级的 R/W
本地服务缓存热点数据 例如:用户会话、文章内容、商品详情
不需要分布式缓存 无需 Redis,直接驻留内存

安装

go get github.com/allegro/bigcache/v3

基本使用示例

package main

import (
	"fmt"
	"time"

	"github.com/allegro/bigcache/v3"
)

func main() {
	cache, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))

	// 存值
	err := cache.Set("user_123", []byte("张三"))
	if err != nil {
		panic(err)
	}

	// 取值
	entry, err := cache.Get("user_123")
	if err != nil {
		fmt.Println("未命中")
	} else {
		fmt.Println("缓存命中:", string(entry)) // 输出: 张三
	}

	// 删除(v3+ 支持)
	cache.Delete("user_123")
}

自定义配置说明

config := bigcache.Config{
    Shards:             1024, // 并发级别:2^N 个分片
    LifeWindow:         5 * time.Minute, // 过期时间
    CleanWindow:        1 * time.Minute, // 清理间隔
    MaxEntrySize:       512, // 最大 value 大小(字节),防止内存碎片
    MaxEntriesInWindow: 1000000, // 预估写入条数
    HardMaxCacheSize:   1024, // 最大内存占用(MB)
    Verbose:            false,
}
cache, _ := bigcache.NewBigCache(config)

性能特点

  • 无 GC 压力:内部使用 []byte 而非 map[string]interface{},避免大对象频繁 GC
  • 高并发性能优异:锁粒度小(分片锁),支持百万级 RPS
  • 内存复用:数据结构复用,减少堆内存碎片
  • 缺点: 不支持复杂查询(如模糊匹配),仅键值访问

注意事项

  • 只支持 []byte,你需要用 json.Marshalgob 手动序列化对象
  • 不支持 TTL 精确到每条记录,仅按 LifeWindow 批量过期
  • 不是分布式缓存,适合单实例或负载均衡中的本地缓存层

实用封装建议

建议封装成一个结构体做序列化:

type CacheStore struct {
    cache *bigcache.BigCache
}

func NewCacheStore() *CacheStore {
    c, _ := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))
    return &CacheStore{cache: c}
}

func (c *CacheStore) SetJSON(key string, val interface{}) error {
    b, _ := json.Marshal(val)
    return c.cache.Set(key, b)
}

func (c *CacheStore) GetJSON(key string, dest interface{}) error {
    b, err := c.cache.Get(key)
    if err != nil {
        return err
    }
    return json.Unmarshal(b, dest)
}

总结对比(vs Go map vs Redis)

特性 map bigcache Redis
并发安全
GC 友好
支持过期
跨进程
性能 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐(网络开销)
典型用途 小量本地缓存 高速本地缓存 分布式共享缓存

下面是一个通用的 BigCacheManager 封装,支持:

  1. 自动序列化 JSON 对象
  2. 自定义缓存时长
  3. 缓存命中/失败日志(可扩展为 Prometheus Metrics)
  4. 支持 fallback 到 Redis(可选接口)

目录结构建议(推荐模块化)

cache/
  bigcache_manager.go
  redis_fallback.go  (可选)

bigcache_manager.go

package cache

import (
	"encoding/json"
	"errors"
	"log"
	"time"

	"github.com/allegro/bigcache/v3"
)

type BigCacheManager struct {
	cache *bigcache.BigCache
}

func NewBigCacheManager(defaultTTL time.Duration) (*BigCacheManager, error) {
	config := bigcache.Config{
		Shards:             1024, // 并发分片数
		LifeWindow:         defaultTTL,
		CleanWindow:        1 * time.Minute,
		MaxEntriesInWindow: 1000000,
		MaxEntrySize:       1024, // bytes
		HardMaxCacheSize:   512,  // MB
		Verbose:            false,
	}

	cache, err := bigcache.NewBigCache(config)
	if err != nil {
		return nil, err
	}

	return &BigCacheManager{cache: cache}, nil
}

// SetJSON - 存入缓存(自动序列化)
func (b *BigCacheManager) SetJSON(key string, val interface{}) error {
	data, err := json.Marshal(val)
	if err != nil {
		return err
	}
	return b.cache.Set(key, data)
}

// GetJSON - 从缓存读取(自动反序列化)
func (b *BigCacheManager) GetJSON(key string, dest interface{}) error {
	data, err := b.cache.Get(key)
	if err != nil {
		if errors.Is(err, bigcache.ErrEntryNotFound) {
			log.Printf("[cache miss] key=%s", key)
			return err
		}
		log.Printf("[cache error] key=%s, err=%v", key, err)
		return err
	}
	return json.Unmarshal(data, dest)
}

// Delete - 删除缓存项
func (b *BigCacheManager) Delete(key string) error {
	return b.cache.Delete(key)
}

使用示例

type User struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	bcm, _ := NewBigCacheManager(10 * time.Minute)

	// 写入缓存
	user := User{ID: 1, Name: "张三", Age: 28}
	bcm.SetJSON("user:1", user)

	// 读取缓存
	var cachedUser User
	err := bcm.GetJSON("user:1", &cachedUser)
	if err == nil {
		fmt.Printf("缓存命中: %+v\n", cachedUser)
	} else {
		fmt.Println("缓存未命中")
	}
}

可选 Redis Fallback 支持(接口定义)

你可以扩展成带 Redis fallback 的版本:

type Cache interface {
	SetJSON(key string, val interface{}) error
	GetJSON(key string, dest interface{}) error
	Delete(key string) error
}

然后再实现一个 RedisCacheManager,并组合调用。


可拓展点

能力 说明
TTL 控制 当前为统一 TTL,可按 key 分类扩展
Metrics 接入 Prometheus 记录命中/失败数
Namespace 支持 加前缀如 user:, item:
并发加载缓存(如 singleflight) 防止缓存击穿

你可能感兴趣的:([每周一更]-(第146期):BigCache使用指南:打造高并发无GC压力的本地缓存)