背景
实际业务场景中有些需求对于数据实时性要求不高,但是对于吞吐量和响应有着极高的要求,这个时候我们可以建立多级缓存来解决此类问题,本篇文章我们讨论的是内存缓存(golang)来实现
实现方案
想到内存缓存,想必大家第一个想到的是golang中的map+mutex、sync.map的方式来实现.
对于读多写少的场景,一般建议大家用sync.map来实现(具体场景的性能测试如下)
引用自: https://blog.csdn.net/wyg_031113/article/details/106282340
code
package bm
import (
"hash/crc32"
"sync"
"time"
)
const (
BucketSize = 256
)
type BigSyncMap struct {
// 分段来存储 数据提供并发访问效率
cacheBuckets [BucketSize]*sync.Map
// 存储每个key的过期时间
expires *sync.Map
}
var (
bigMap *BigSyncMap
once sync.Once
)
// GetBigSyncMapInstance 获取实例
func GetBigSyncMapInstance() *BigSyncMap {
once.Do(func() {
bigMap = &BigSyncMap{
expires: &sync.Map{},
}
for i := 0; i < BucketSize; i++ {
bigMap.cacheBuckets[i] = &sync.Map{}
}
// 开启携程 定时清除过期的data
go bigMap.flushExpireData()
})
return bigMap
}
func (m *BigSyncMap) flushExpireData() {
for {
m.expires.Range(func(key, expireTime interface{}) bool {
if time.Since(expireTime.(time.Time)) > time.Minute*30 {
m.delete(key.(string))
}
return true
})
time.Sleep(time.Minute * 2)
}
}
func (m *BigSyncMap) delete(key string) {
m.cacheBuckets[checksum(key)].Delete(key)
}
// checksum 根据crc32算法取key的index
func checksum(key string) int {
return int(crc32.ChecksumIEEE([]byte(key)) % BucketSize)
}
// Load 加载数据
func (m *BigSyncMap) Load(key interface{}) (interface{}, bool) {
return m.cacheBuckets[checksum(key.(string))].Load(key)
}
// Store 存储数据,并更新对应key的expire time
func (m *BigSyncMap) Store(key, val interface{}) {
m.cacheBuckets[checksum(key.(string))].Store(key,val)
m.expires.Store(key,time.Now())
}