Skip to main content

缓存组件

概要#

缓存组件组要包括本地缓存和分布式缓存,两个组件都实现以下接口

type Cache interface {  Set(ctx context.Context, key string, val interface{}, expiration time.Duration) error  Get(ctx context.Context, key string, val interface{}) error  MultiSet(ctx context.Context, valMap map[string]interface{}, expiration time.Duration) error  MultiGet(ctx context.Context, keys []string, valueMap interface{}) error  Del(ctx context.Context, keys ...string) error  SetCacheWithNotFound(ctx context.Context, key string) error}

本地缓存使用#

内部主要使用 ristretto

初始化#

func NewMemoryCache(keyPrefix string, encoding encoding.Encoding) Cache {  config := &ristretto.Config{    NumCounters: 1e7,     // number of keys to track frequency of (10M).    MaxCost:     1 << 30, // maximum cost of cache (1GB).    BufferItems: 64,      // number of keys per Get buffer.  }  store, _ := ristretto.NewCache(config)  return &memoryCache{    client:    store,    KeyPrefix: keyPrefix,    encoding:  encoding,  }}

Example#

  store := NewMemoryCache("memory-unit-test", encoding.JSONEncoding{})  ctx := context.Background()  var gotVal string  store.Set(ctx, "test-get-key", "test", 3600)  store.Get(ctx, "test-get-key", &gotVal)

分布式缓存使用#

内部主要使用 redis

初始化#

func NewRedisCache(client *redis.Client, keyPrefix string, encoding encoding.Encoding, newObject func() interface{}) Cache {  return &redisCache{    client:    client,    KeyPrefix: keyPrefix,    encoding:  encoding,    newObject: newObject,  }}

Example#

  ...  // 获取redis客户端  redisClient := redis.GetRedisClient()  // 实例化redis cache  // 指定编码格式为 json  cache := NewRedisCache(redisClient, "test-key", encoding.JSONEncoding{}, func() interface{} {    return new(int64)  })  ...

如何在业务中使用#

可以参考以下案例,代码使用工具生成

# 生成命令eagle cache add UserCache
package cache
//go:generate mockgen -source=user_cache.go -destination=../../internal/mock/user_cache_mock.go  -package mock
import (  "context"  "fmt"  "time"
  "github.com/spf13/cast"
  "github.com/go-eagle/eagle/pkg/cache"  "github.com/go-eagle/eagle/pkg/encoding"  "github.com/go-eagle/eagle/pkg/log"  "github.com/go-redis/redis/v8"
  "github.com/go-microservice/user-service/internal/model")
const (  // PrefixUserCacheKey cache prefix  PrefixUserCacheKey = "user:%d")
type UserCache interface {  SetUserCache(ctx context.Context, id int64, data *model.UserModel, duration time.Duration) error  GetUserCache(ctx context.Context, id int64) (ret *model.UserModel, err error)  MultiGetUserCache(ctx context.Context, ids []int64) (map[string]*model.UserModel, error)  MultiSetUserCache(ctx context.Context, data []*model.UserModel, duration time.Duration) error  DelUserCache(ctx context.Context, id int64) error  SetCacheWithNotFound(ctx context.Context, id int64) error}
// userCache define a cache structtype userCache struct {  cache cache.Cache}
// NewUserCache new a cachefunc NewUserCache(rdb *redis.Client) UserCache {  jsonEncoding := encoding.JSONEncoding{}  cachePrefix := ""  return &userCache{    cache: cache.NewRedisCache(rdb, cachePrefix, jsonEncoding, func() interface{} {      return &model.UserModel{}    }),  }}
// GetUserCacheKey get cache keyfunc (c *userCache) GetUserCacheKey(id int64) string {  return fmt.Sprintf(PrefixUserCacheKey, id)}
// SetUserCache write to cachefunc (c *userCache) SetUserCache(ctx context.Context, id int64, data *model.UserModel, duration time.Duration) error {  if data == nil || id == 0 {    return nil  }  cacheKey := c.GetUserCacheKey(id)  err := c.cache.Set(ctx, cacheKey, data, duration)  if err != nil {    return err  }  return nil}
// GetUserCache 获取cachefunc (c *userCache) GetUserCache(ctx context.Context, id int64) (ret *model.UserModel, err error) {  var data *model.UserModel  cacheKey := c.GetUserCacheKey(id)  err = c.cache.Get(ctx, cacheKey, &data)  if err != nil {    log.WithContext(ctx).Warnf("get err from redis, err: %+v", err)    return nil, err  }  return data, nil  }
// MultiGetUserCache 批量获取cachefunc (c *userCache) MultiGetUserCache(ctx context.Context, ids []int64) (map[string]*model.UserModel, error) {  var keys []string  for _, v := range ids {    cacheKey := c.GetUserCacheKey(v)    keys = append(keys, cacheKey)  }
// NOTE: 需要在这里make实例化,如果在返回参数里直接定义会报 nil mapitemMap := make(map[string]*model.UserModel)  err := c.cache.MultiGet(ctx, keys, itemMap)  if err != nil {    return nil, err  }
  retMap := make(map[string]*model.UserModel)  for _, v := range ids {    val, ok := itemMap[c.GetUserCacheKey(v)]    if ok {      retMap[cast.ToString(v)] = val    }  }  return retMap, nil}
// MultiSetUserCache 批量设置cachefunc (c *userCache) MultiSetUserCache(ctx context.Context, data []*model.UserModel, duration time.Duration) error {  valMap := make(map[string]interface{})  for _, v := range data {    cacheKey := c.GetUserCacheKey(v.ID)    valMap[cacheKey] = v  }
  err := c.cache.MultiSet(ctx, valMap, duration)  if err != nil {    return err  }  return nil}
// DelUserCache 删除cachefunc (c *userCache) DelUserCache(ctx context.Context, id int64) error {  cacheKey := c.GetUserCacheKey(id)  err := c.cache.Del(ctx, cacheKey)  if err != nil {    return err  }  return nil}
// DelUserCache set empty cachefunc (c *userCache) SetCacheWithNotFound(ctx context.Context, id int64) error {  cacheKey := c.GetUserCacheKey(id)  err := c.cache.SetCacheWithNotFound(ctx, cacheKey)  if err != nil {    return err  }  return nil}

来源: https://github.com/go-microservice/user-service/blob/main/internal/cache/user_cache.go

Reference#