# 4.9 调用本地缓存

# 4.9.1 简介

pkg/cache/xfreecache 包是对freecache库进行二次封装,用于本地缓存并支持metric上报

frercache特性:

  • 可存储数以百万计条目
  • 零垃圾收集负荷
  • 高并发而且线程安全的访问
  • 纯 Go 语言实现
  • 支持对象失效
  • 近乎 LRU 的算法
  • 严格限制内存使用

# 4.9.2 注意事项

  • 缓存key的大小需要小于65535,否则无法存入到本地缓存中(The key is larger than 65535)
  • 缓存value的大小需要小于缓存总容量的1/1024,否则无法存入到本地缓存中(The entry size need less than 1/1024 of cache size)

# 4.9.3 使用泛型的用法(推荐)

# 1 初始化实例

# 1) 配置规范

[jupiter.cache]
    # 本地缓存总容量 默认256MB 
    # 缓存value的大小需要小于缓存总容量的1/1024,否则无法存入到本地缓存中
    # 可支持单位: B或Btye、KB、MB、GB、TB (大小写均支持)
    size = "256MB" 
[jupiter.cache.student]
    expire = "2m" # 本地缓存失效时间
    disableMetric = false # 是否禁用metric上报 false 开启  ture 关闭  默认开启上报
1
2
3
4
5
6
7
8

# 2) 初始化方式

import (
    "github.com/douyu/jupiter/pkg/cache/xfreecache/v2"
)

type Student struct {
    Age  int
    Name string
}

type Instance struct {
	localCache *xfreecache.LocalCache[string, Student]
}

func NewInstance() *Instance {
	return &Instance{
		localCache: xfreecache.StdNew[string, Student]("student"),
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 若juno中无配置时,会初始化一个默认配置。默认配置详情:缓存容量:256MB(缓存value需要小于256KB) 失效时间:2分钟 是否开启metric上报:
  • 初始化多个配置时,内部只会初始化一个缓存容量为256MB的缓存实例。无需担心初始化多个实例后的缓存消耗

# 2 函数方法介绍

// GetAndSetCacheData 获取缓存后数据(内部已封装设置和获取本地缓存操作)【推荐使用】
// key 缓存key
// id 索引(无作用,会组装到key里面)
// fn 获取返回数据需要执行的方法
// value 
// err fn返回的错误以及其他报错
func (c *cache[K, V]) GetAndSetCacheData(key string, id K, fn func() (V, error)) (value V, err error)

// GetCacheValue 获取缓存数据
// key 缓存key
// id 索引(无作用,会组装到key里面)
// value 
func (c *cache[K, V]) GetCacheValue(key string, id K) (value V)

// SetCacheValue 设置缓存数据
// key 缓存key
// id 索引(无作用,会组装到key里面)
// fn 获取返回数据需要执行的方法
// err fn返回的错误以及其他报错
func (c *cache[K, V]) SetCacheValue(key string, id K, fn func() (V, error)) (err error)

// GetAndSetCacheMap 获取缓存后数据 map形式 【推荐使用】
// key 缓存key
// ids 返回map中的key集合
// fn 获取返回数据需要执行的方法
// value 
// err fn返回的错误以及其他报错
func (c *cache[K, V]) GetAndSetCacheMap(key string, ids []K, fn func([]K) (map[K]V, error)) (v map[K]V, err error)

// GetCacheMap 获取缓存数据 map形式
// key 缓存key
// ids 返回map中的key集合
// value 
func (c *cache[K, V]) GetCacheMap(key string, ids []K) (v map[K]V)

// SetCacheMap 设置缓存数据 map形式
// key 缓存key
// ids 返回map中的key集合
// fn 获取返回数据需要执行的方法
// err fn返回的错误以及其他报错
func (c *cache[K, V]) SetCacheMap(key string, ids []K, fn func([]K) (map[K]V, error)) (err error)

// SetCacheData 设置本地缓存
// key 缓存key
// data 缓存value,传入序列化后的字节数组
func SetCacheData(key string, data []byte)

// GetCacheData 获取本地缓存
// key 缓存key
// data 缓存value
// err error
func GetCacheData(key string) (data []byte, err error) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

# 3 实际案例

配置项

[jupiter.cache.bwlist]
    expire = "1m" # 本地缓存失效时间
1
2

代码

package bwlist

import (
	"context"
	"github.com/douyu/jupiter/pkg/cache/xfreecache/v2"
)

type Instance struct {
	localCache *xfreecache.LocalCache[int32, []int32]
}

func NewInstance() *Instance {
	return &Instance{
		localCache: xfreecache.StdNew[int32, []int32]("bwlist"),
	}
}

// GetBWListCached 获取单个白名单配置-带1min本地缓存
// id 白名单配置id
func (i *Instance) GetBWListCached(ctx context.Context, id int32) (res []int32, err error) {
	res, err = i.localCache.GetAndSetCacheData("bwlist.GetBWList", id, func() ([]int32, error) {
		data, innerErr := i.GetBWList(ctx, id)
		return data, innerErr
	})
	return
}

// BatchGetBWListCached 批量获取白名单配置-带1min本地缓存
// ids 多个白名单配置id
func (i *Instance) BatchGetBWListCached(ctx context.Context, ids []int32) (res map[int32][]int32, err error) {
	res, err = i.localCache.GetAndSetCacheMap("bwlist.GetBWList", ids, func(innerIds []int32) (map[int32][]int32, error) {
		data, innerErr := i.BatchGetBWList(ctx, innerIds)
		return data, innerErr
	})
	return
}

// GetBWList 获取单个白名单配置-不带缓存
// id 白名单配置id
func (i *Instance) GetBWList(ctx context.Context, id int32) (res []int32, err error) {
	// TODO 可以根据实际业务具体实现方法
	return
}

// BatchGetBWList 批量获取白名单配置-不带缓存
// ids 多个白名单配置id
func (i *Instance) BatchGetBWList(ctx context.Context, id []int32) (res map[int32][]int32, err error) {
	// TODO 可以根据实际业务具体实现方法
	return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

# 4.9.4 不使用泛型的用法(返回字节数组,需要自己实现序列化)

# 1 初始化实例

# 1) 使用默认的初始化方式

  • 初始化方式
type Instance struct {
	localCache *xfreecache.LocalCache
}

func NewInstance() *Instance {
	return &Instance{
		localCache: xfreecache.DefaultConfig().Build(),
	}
}
1
2
3
4
5
6
7
8
9
  • 默认配置详情:缓存容量:256MB(缓存value需要小于256KB) 失效时间:2分钟 是否开启metric上报:
type Config struct {
	Size          Size          // 缓存容量,最小512*1024 【必填】
	Expire        time.Duration // 失效时间 【必填】
	DisableMetric bool          // metric上报 false 开启  ture 关闭【选填,默认开启】
	Name          string        // 本地缓存名称,用于日志标识&metric上报【选填】
}

// DefaultConfig 返回默认配置
func DefaultConfig() Config {
	return Config{
		Size:          256 * MB,
		Expire:        2 * time.Minute,
		DisableMetric: false,
		Name:          fmt.Sprintf("cache-%d", time.Now().UnixNano()),
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 2) 自定义初始化方式

func NewInstance() *Instance {
	return &Instance{
		localCache: xfreecache.Config{
			Size:          128 * xfreecache.MB,
			Expire:        2 * time.Minute,
			DisableMetric: false,
			Name:          "bwList",
		}.Build(),
	}
}
1
2
3
4
5
6
7
8
9
10

# 2 函数方法介绍

// GetAndSetCacheData 获取缓存后数据(内部已封装设置和获取本地缓存操作)【推荐使用】
// key 缓存key
// fn 获取返回数据需要执行的方法
// err fn返回的错误以及其他报错
func GetAndSetCacheData(key string, fn func() ([]byte, error)) (v []byte, err error)

// SetCacheData 设置本地缓存
// key 缓存key
// data 缓存value,传入序列化后的字节数组
func SetCacheData(key string, data []byte)

// GetCacheData 获取本地缓存
// key 缓存key
// data 缓存value
// err error
func GetCacheData(key string) (data []byte, err error) 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3 实际案例

package bwlist

import (
	"context"
	"encoding/json"
	"fmt"
	"time"

	"git.dz11.com/vega/minerva/log"
	"github.com/douyu/jupiter/pkg/cache/xfreecache"
	"go.uber.org/zap"
)

type Instance struct {
	localCache *xfreecache.LocalCache
}

func NewInstance() *Instance {
	return &Instance{
		localCache: xfreecache.Config{
			Size:          128 * xfreecache.MB,
			Expire:        2 * time.Minute,
			DisableMetric: false,
			Name:          "bwList",
		}.Build(),
	}
}

type GetBWListRequest struct {
	// 黑白名单ID
	Id int32 `protobuf:"varint,1,opt,name=id" json:"id,omitempty"`
	// 1 白名单 2 黑名单
	LimitType int32 `protobuf:"varint,3,opt,name=limit_type,json=limitType" json:"limit_type,omitempty"`
}

func (i *Instance) GetBWListCached(ctx context.Context, req *GetBWListRequest) (res []int32, err error) {
	cacheKey := fmt.Sprintf("bwlist.GetBWList:%d:%d", req.Id, req.LimitType)
	data, err := i.localCache.GetAndSetCacheData(cacheKey, func() ([]byte, error) {
		data, innerErr := i.GetBWList(ctx, req)
		ret, _ := json.Marshal(data)
		return ret, innerErr
	})
	err = json.Unmarshal(data, &res)
	if err != nil {
		log.L(ctx).Error("bwlist GetBWListCached Unmarshal", zap.Any("req", req), zap.Error(err))
	}
	return
}

func (i *Instance) GetBWList(ctx context.Context, req *GetBWListRequest) (res []int32, err error) {
	// 可以根据实际业务具体实现方法
	res = []int32{123456}
	return
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54

# 4.9.5 juno监控

image