golang高性能内存缓存支持过期与分片插件库imcache的使用
Golang高性能内存缓存支持过期与分片插件库imcache的使用
imcache是一个零依赖的通用内存缓存Go库,支持绝对过期、滑动过期、最大条目限制、驱逐回调和分片功能。它是并发安全的,可以被多个goroutine同时使用。
基本用法
package main
import (
"fmt"
"github.com/erni27/imcache"
)
func main() {
// 零值Cache是一个有效的非分片缓存
// 没有过期时间,没有滑动过期,
// 没有条目限制和没有驱逐回调
var c imcache.Cache[uint32, string]
c.Set(1, "one", imcache.WithNoExpiration())
value, ok := c.Get(1)
if !ok {
panic("value for the key '1' not found")
}
fmt.Println(value)
}
过期策略
imcache支持以下过期选项:
WithNoExpiration
- 条目永不过期WithExpiration
- 条目在一定时间后过期WithExpirationDate
- 条目在特定日期过期WithSlidingExpiration
- 如果条目未被访问,则在一定时间后过期。每次访问条目时,过期时间会重置为当前时间加上滑动过期时间
// 条目永不过期
c.Set(1, "one", imcache.WithNoExpiration())
// 条目在1秒后过期
c.Set(2, "two", imcache.WithExpiration(time.Second))
// 条目在指定日期过期
c.Set(3, "three", imcache.WithExpirationDate(time.Now().Add(time.Second)))
// 如果条目未被访问,则在1秒后过期
// 否则,过期时间将滑动到访问时间+1秒
c.Set(4, "four", imcache.WithSlidingExpiration(time.Second))
键驱逐
imcache会主动驱逐过期条目。当通过大多数Cache
方法(读写操作)访问条目时,会移除过期条目。Peek
、PeekMultiple
和PeekAll
方法是例外,它们不会移除过期条目,也不会滑动过期时间(如果设置了滑动过期)。
可以使用Cleaner
定期从缓存中移除过期条目。Cleaner
是一个后台goroutine,定期从缓存中移除过期条目。默认情况下Cleaner
是禁用的。可以使用WithCleanerOption
选项启用Cleaner
并设置清理间隔。
// 创建一个新的Cache,带有每5分钟清理一次过期条目的Cleaner
c := imcache.New[string, string](imcache.WithCleanerOption[string, string](5 * time.Minute))
// 关闭Cache。如果Cleaner正在运行,这将停止它
defer c.Close()
最大条目限制
imcache支持设置最大条目限制。当达到最大条目限制时,根据选择的驱逐策略驱逐条目。imcache支持以下驱逐策略:
EvictionPolicyLRU
- 驱逐最近最少使用的条目EvictionPolicyLFU
- 驱逐最不经常使用的条目EvictionPolicyRandom
- 随机驱逐一个条目
可以使用WithMaxEntriesLimitOption
选项为给定的缓存实例设置最大条目限制和驱逐策略。
c := imcache.New[uint32, string](imcache.WithMaxEntriesLimitOption[uint32, string](1000, imcache.EvictionPolicyLRU))
分片
imcache支持分片。每个分片是一个单独的Cache
实例。通过计算键的哈希值并对分片数取模来选择给定键的分片。imcache公开了Hasher64
接口,可用于实现自定义分片算法。
可以通过调用NewSharded
方法创建一个Sharded
实例。
c := imcache.NewSharded[string, string](4, imcache.DefaultStringHasher64{})
完整示例
package main
import (
"log"
"time"
"github.com/erni27/imcache"
)
func LogEvictedEntry(key string, value interface{}, reason imcache.EvictionReason) {
log.Printf("Evicted entry: %s=%v (%s)", key, value, reason)
}
func main() {
// 创建一个带有1秒默认过期时间和驱逐回调的缓存
c := imcache.New[string, interface{}](
imcache.WithDefaultExpirationOption[string, interface{}](time.Second),
imcache.WithEvictionCallbackOption[string, interface{}](LogEvictedEntry),
)
c.Set("foo", "bar", imcache.WithDefaultExpiration())
time.Sleep(time.Second)
_, ok := c.Get("foo")
if ok {
panic("expected entry to be expired")
}
}
性能
imcache与具有简单锁定机制的普通Go map进行了比较。基准测试在Apple M1 Pro 8核CPU、32GB内存、macOS Ventura 13.4.1上运行,使用Go 1.21.6。
读取性能
BenchmarkCache_Get-8 2655246 428.5 ns/op
BenchmarkSharded_Get/2_Shards-8 2810713 436.8 ns/op
BenchmarkSharded_Get/4_Shards-8 2732820 444.9 ns/op
BenchmarkSharded_Get/8_Shards-8 2957444 445.7 ns/op
BenchmarkSharded_Get/16_Shards-8 2773999 447.0 ns/op
BenchmarkSharded_Get/32_Shards-8 2752075 443.4 ns/op
BenchmarkSharded_Get/64_Shards-8 2752899 439.7 ns/op
BenchmarkSharded_Get/128_Shards-8 2771691 456.3 ns/op
写入性能
BenchmarkCache_Set-8 2942062 461.7 ns/op
BenchmarkSharded_Set/2_Shards-8 2939275 487.5 ns/op
BenchmarkSharded_Set/4_Shards-8 2827146 497.1 ns/op
BenchmarkSharded_Set/8_Shards-8 2837316 509.1 ns/op
BenchmarkSharded_Set/16_Shards-8 2818513 495.7 ns/op
BenchmarkSharded_Set/32_Shards-8 2793490 506.3 ns/op
BenchmarkSharded_Set/64_Shards-8 2815544 499.7 ns/op
BenchmarkSharded_Set/128_Shards-8 2738779 511.2 ns/op
imcache提供了高性能的内存缓存解决方案,支持多种过期策略和分片功能,非常适合需要高性能缓存的Go应用程序。
更多关于golang高性能内存缓存支持过期与分片插件库imcache的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang高性能内存缓存支持过期与分片插件库imcache的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang高性能内存缓存库imcache使用指南
imcache是一个高性能的Go内存缓存库,支持过期时间和分片功能。下面我将详细介绍如何使用imcache。
基本特性
- 支持键值过期(TTL)
- 自动清理过期项目
- 分片支持提高并发性能
- 简单易用的API
安装
go get github.com/erni27/imcache
基本使用
1. 创建缓存
package main
import (
"fmt"
"time"
"github.com/erni27/imcache"
)
func main() {
// 创建一个简单的缓存
cache := imcache.New[string, string]()
// 设置带过期时间的值
cache.Set("key1", "value1", imcache.WithDefaultExpiration())
// 设置自定义过期时间
cache.Set("key2", "value2", imcache.WithExpiration(time.Hour))
// 获取值
if val, ok := cache.Get("key1"); ok {
fmt.Println("Got value:", val)
}
// 删除键
cache.Delete("key1")
}
2. 带分片的缓存
func main() {
// 创建带分片的缓存(16个分片)
shardedCache := imcache.NewSharded[string, int](16)
// 并发设置值
for i := 0; i < 100; i++ {
go func(i int) {
key := fmt.Sprintf("key%d", i)
shardedCache.Set(key, i, imcache.WithExpiration(time.Minute))
}(i)
}
time.Sleep(time.Second) // 等待goroutine完成
// 获取所有值
for i := 0; i < 100; i++ {
key := fmt.Sprintf("key%d", i)
if val, ok := shardedCache.Get(key); ok {
fmt.Printf("%s: %d\n", key, val)
}
}
}
3. 高级配置
func main() {
// 自定义配置
cache := imcache.New[string, interface{}](
imcache.WithDefaultExpirationOption(time.Minute*5), // 默认过期时间
imcache.WithCleanupIntervalOption(time.Minute), // 清理间隔
imcache.WithOnEvictedFunc(func(key string, value interface{}) {
fmt.Printf("Key %s evicted\n", key)
}),
)
cache.Set("user:1001", map[string]interface{}{
"name": "Alice",
"email": "alice@example.com",
}, imcache.WithExpiration(time.Hour))
if user, ok := cache.Get("user:1001"); ok {
fmt.Println("User:", user)
}
}
4. 性能优化技巧
-
合理设置分片数量:根据CPU核心数和并发量设置
// 通常设置为CPU核心数的2-4倍 shardedCache := imcache.NewSharded[string, int](runtime.NumCPU() * 2)
-
批量操作:
// 批量设置 items := map[string]string{ "key1": "value1", "key2": "value2", } for k, v := range items { cache.Set(k, v, imcache.WithDefaultExpiration()) }
-
使用指针类型存储大对象减少拷贝:
type BigStruct struct { // 大字段 } cache := imcache.New[string, *BigStruct]() bigObj := &BigStruct{...} cache.Set("big", bigObj, imcache.WithDefaultExpiration())
注意事项
- imcache是内存缓存,重启后数据会丢失
- 大量数据可能导致内存压力,需监控内存使用
- 对于复杂查询需求,可能需要结合其他数据结构
imcache适合作为应用层的快速缓存解决方案,特别是需要高并发访问的场景。对于分布式环境,可以考虑结合Redis等分布式缓存使用。