golang高效处理GB级数据的键值缓存插件库BigCache的使用

Golang高效处理GB级数据的键值缓存插件库BigCache的使用

简介

BigCache是一个快速、并发、支持淘汰机制的内存缓存库,专门设计用于存储大量条目而不影响性能。BigCache将条目保存在堆上但避免了GC对它们的影响。为了实现这一点,它使用字节切片进行操作,因此在大多数用例中需要在缓存前后进行条目的(反)序列化。

要求Go 1.12或更高版本。

基本使用

简单初始化

import (
	"fmt"
	"context"
	"github.com/allegro/bigcache/v3"
	"time"
)

// 创建一个生命周期为10分钟的缓存
cache, _ := bigcache.New(context.Background(), bigcache.DefaultConfig(10 * time.Minute))

// 设置键值
cache.Set("my-unique-key", []byte("value"))

// 获取值
entry, _ := cache.Get("my-unique-key")
fmt.Println(string(entry))  // 输出: value

自定义初始化

当可以提前预测缓存负载时,最好使用自定义初始化,这样可以避免额外的内存分配。

import (
	"log"
	"time"
	"github.com/allegro/bigcache/v3"
)

config := bigcache.Config {
		// 分片数量(必须是2的幂)
		Shards: 1024,

		// 条目可以被淘汰的时间
		LifeWindow: 10 * time.Minute,

		// 清理过期条目的时间间隔
		// 如果设置为<=0则不执行任何操作
		// 设置为<1秒会适得其反,因为bigcache有1秒的分辨率
		CleanWindow: 5 * time.Minute,

		// rps * lifeWindow, 仅用于初始内存分配
		MaxEntriesInWindow: 1000 * 10 * 60,

		// 最大条目大小(字节),仅用于初始内存分配
		MaxEntrySize: 500,

		// 打印关于额外内存分配的信息
		Verbose: true,

		// 缓存不会分配超过此限制的内存,单位为MB
		// 如果达到此值,则可以为新条目覆盖最旧的条目
		// 0表示没有大小限制
		HardMaxCacheSize: 8192,

		// 当最旧的条目由于过期时间或没有空间而被移除时触发的回调
		// 将返回一个表示原因的位掩码
		// 默认值为nil,表示没有回调
		OnRemove: nil,

		// OnRemoveWithReason是一个回调,当最旧的条目由于过期时间或没有空间而被移除时触发
		// 将传递一个表示原因的常量
		// 默认值为nil,表示没有回调
		// 如果指定了OnRemove,则忽略此选项
		OnRemoveWithReason: nil,
	}

cache, initErr := bigcache.New(context.Background(), config)
if initErr != nil {
	log.Fatal(initErr)
}

cache.Set("my-unique-key", []byte("value"))

if entry, err := cache.Get("my-unique-key"); err == nil {
	fmt.Println(string(entry))
}

LifeWindow 和 CleanWindow

  1. LifeWindow 是一个时间。超过这个时间后,条目可以被视为死亡但不会被删除。
  2. CleanWindow 是一个时间。超过这个时间后,所有死亡的条目将被删除,但仍有生命的条目不会被删除。

性能比较

BigCache与freecache和原生map进行了比较。基准测试使用i7-6700K CPU @ 4.00GHz和32GB RAM在Ubuntu 18.04 LTS(5.2.12-050212-generic)上进行。

写入和读取性能

BenchmarkMapSet-8                     12999889	       376 ns/op
BenchmarkConcurrentMapSet-8           4355726	      1275 ns/op
BenchmarkFreeCacheSet-8               11068976	       703 ns/op
BenchmarkBigCacheSet-8                10183717	       478 ns/op
BenchmarkMapGet-8                     16536015	       324 ns/op
BenchmarkConcurrentMapGet-8           13165708	       401 ns/op
BenchmarkFreeCacheGet-8               10137682	       690 ns/op
BenchmarkBigCacheGet-8                11423854	       450 ns/op

BigCache的写入和读取速度比freecache快。写入map是最慢的。

GC暂停时间

Number of entries:  20000000
GC pause for bigcache:  1.506077ms
GC pause for freecache:  5.594416ms
GC pause for map:  9.347015ms

测试显示了填充2000万条目时GC暂停的时间长度。Bigcache和freecache有非常相似的GC暂停时间。

工作原理

BigCache依赖于Go 1.5版本中提出的优化。这种优化指出,如果在键和值中没有指针的map被使用,那么GC将忽略其内容。因此BigCache使用map[uint64]uint32,其中键是哈希值,值是条目的偏移量。

条目保存在字节切片中,再次避免GC。字节切片的大小可以增长到GB级别而不影响性能,因为GC只会看到它的单个指针。

碰撞处理

BigCache不处理碰撞。当插入新项目并且其哈希与先前存储的项目碰撞时,新项目将覆盖先前存储的值。

BigCache vs FreeCache

两种缓存都提供相同的核心功能,但它们以不同的方式减少GC开销。BigCache依赖于map[uint64]uint32,freecache实现了自己的基于切片的映射以减少指针数量。

BigCache相对于freecache的一个优势是您不需要提前知道缓存的大小,因为当bigcache已满时,它可以为新条目分配额外的内存,而不是像freecache当前所做的那样覆盖现有条目。但是也可以在bigcache中设置硬最大大小。

HTTP服务器

此包还包括一个易于部署的BigCache HTTP实现,可以在server包中找到。

许可证

BigCache在Apache 2.0许可证下发布。


更多关于golang高效处理GB级数据的键值缓存插件库BigCache的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang高效处理GB级数据的键值缓存插件库BigCache的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Golang高效处理GB级数据的键值缓存:BigCache使用指南

BigCache是一个专为Golang设计的高性能键值缓存库,特别适合处理GB级别的缓存数据。它通过优化内存分配和减少GC压力,实现了极高的吞吐量。

BigCache核心特性

  1. 零GC压力:使用map[uint64]uint32和自定义内存分配机制避免GC扫描
  2. 高并发:分片设计减少锁竞争
  3. 高效内存利用:预分配内存减少碎片
  4. 简单API:类似标准map的操作接口

安装BigCache

go get github.com/allegro/bigcache/v3

基本使用示例

package main

import (
	"fmt"
	"time"
	
	"github.com/allegro/bigcache/v3"
)

func main() {
	// 创建缓存实例
	cache, err := bigcache.NewBigCache(bigcache.DefaultConfig(10 * time.Minute))
	if err != nil {
		panic(err)
	}

	// 设置缓存
	err = cache.Set("key1", []byte("value1"))
	if err != nil {
		fmt.Println("Set error:", err)
	}

	// 获取缓存
	entry, err := cache.Get("key1")
	if err != nil {
		fmt.Println("Get error:", err)
	} else {
		fmt.Printf("Got value: %s\n", entry)
	}

	// 删除缓存
	err = cache.Delete("key1")
	if err != nil {
		fmt.Println("Delete error:", err)
	}
}

高级配置选项

config := bigcache.Config{
	// 缓存存活时间
	LifeWindow: 10 * time.Minute,
	
	// 清理过期缓存的间隔
	CleanWindow: 5 * time.Minute,
	
	// 分片数量(必须是2的幂)
	Shards: 1024,
	
	// 最大缓存条目数(仅在初始分配内存时使用)
	MaxEntriesInWindow: 1000 * 10 * 60,
	
	// 最大条目大小(字节)
	MaxEntrySize: 500,
	
	// 是否统计缓存命中率
	StatsEnabled: true,
	
	// 当缓存满时的回调函数
	OnRemove: func(key string, entry []byte) {
		fmt.Printf("Evicted: %s\n", key)
	},
	
	// 是否在删除时复制值(安全但性能较低)
	HardMaxCacheSize: 8192, // MB
}

cache, err := bigcache.NewBigCache(config)

性能优化技巧

  1. 合理设置分片数:默认1024分片适合大多数场景,高并发场景可增加
  2. 预分配内存:根据数据量设置MaxEntriesInWindow减少扩容开销
  3. 批量操作:减少锁竞争
// 批量写入示例
func batchSet(cache *bigcache.BigCache, data map[string][]byte) error {
	for k, v := range data {
		if err := cache.Set(k, v); err != nil {
			return err
		}
	}
	return nil
}

监控与统计

// 启用统计后可以获取缓存指标
stats := cache.Stats()
fmt.Printf("Hits: %d, Misses: %d, DelHits: %d, DelMisses: %d\n",
	stats.Hits, stats.Misses, stats.DelHits, stats.DelMisses)

实际应用场景

  1. 会话存储:快速存取用户会话数据
  2. API响应缓存:缓存频繁请求的API结果
  3. 计算中间结果缓存:存储耗时计算的中间结果

与标准map和sync.Map对比

特性 BigCache sync.Map 标准map
GC友好 部分
并发安全
大数据量
内存效率
复杂查询 简单 中等 灵活

注意事项

  1. BigCache不适合存储需要复杂查询的数据
  2. 值只能是[]byte类型,需要自行序列化
  3. 没有自动持久化功能,重启后数据会丢失

通过合理配置和使用BigCache,可以在Golang应用中高效处理GB级别的缓存数据,同时保持极低的GC压力和极高的吞吐量。

回到顶部