首页 > 其他分享 >kratos中使用rockscache介绍

kratos中使用rockscache介绍

时间:2023-02-14 21:47:27浏览次数:52  
标签:缓存 kratos redis 42 介绍 rockscache 2023 id

✅ 包版本问题

注意包版本的问题,因为rockscache需要使用go-redis v8版本的Client,但是如果项目使用的是v9版本的话会有问题(文档中有),我是把官网的项目下载
下来了,(改动说明文档中有),其实就是少了一个Context方法多了一个其他的方法~

# 改动说明

rockscache官方地址:https://github.com/dtm-labs/rockscache

rockscache官方源码使用go-redis v8版本,拉到本地使用v9版本的go-redis并对其中的几个方法(Fetch、FetchBatch与TagAsDeletedBatch)做了简单的修改:
需要在调用的时候加上业务中的ctx。

之前只有 FetchBatch与TagAsDeletedBatch 这2个方法需要用 rdb.Client.Context() 初始化一下ctx,
现在将这2个方法也改成了需要传业务的ctx ,不影响原包的基本功能。

go-redis v9版本与v8版本的 redis.UniversalClient 接口不一样:
v9版本没有 Context 方法,多了一个 SSubscribe 方法,两个interface不一样。

✅ 使用场景建议

建议在"读多写少或有热key"的场景用rockscache,写操作多的话虽然可以使用Write-Through 结合分布式锁的方案但是也会影响性能。
举例:
在用户的账户系统中,所有用户的充值、道具的操作都会修改主账户的数据,主账户的数据写操作比较多,所以如果把
主账户的数据也放到redis中,需要加额外的影响性能的代码,而且考虑到主账户的数据量不是特别大,倒不如只将主账户的数据存到数据库中,只修改数据库的数据;
其他的一些有热key访问并且该key对应的数据需要一定的后台计算时间的场景,建议使用rockscache。

✅ 简单的用法及存储的改变

1、初始化及用法:

  • 项目中封装初始化,需要用到go-redis Client
  • 项目中使用:简单的get接口,用Fetch2那个方法讲解

2、存储的改变~在里面都存成了hash —— 因为内部使用lua一次执行,执行的过程中其他脚本或命令无法执行,而且同时保存 key/valuekey/lock

// rockscache将string数据存成了hash类型,比如说,我们之前在redis中存的数据是string,用get方法获取:
```
get countValue1
"{\"id\":\"1\",\"count\":100,\"createTime\":\"2023-02-13T11:42:42+08:00\",\"updateTime\":\"2023-02-13T11:42:42+08:00\"}"
```

// 使用rockescache的话变成了hash,用hgetall方法获取:
```
hgetall countCache1
1) "value"
2) "{\"id\":\"1\",\"count\":100,\"createTime\":\"2023-02-13T11:42:42+08:00\",\"updateTime\":\"2023-02-13T11:42:42+08:00\"}"
```

✅ 配置项说明

1-1、详细讲一下那些配置项

func NewRocksCache(c *conf.Data, logger log.Logger, rdb *redis.Client) *rockscache_local.Client {
	var dc = rockscache_local.NewClient(rdb, rockscache_local.NewDefaultOptions())
	// 常用参数设置
	// 1、强一致性(默认关闭强一致性,如果开启的话会影响性能)
	dc.Options.StrongConsistency = false

	// 2、redis出现问题需要缓存降级时设置为true
	dc.Options.DisableCacheRead = false   // 关闭缓存读,默认false;如果打开,那么Fetch就不从缓存读取数据,而是直接调用fn获取数据
	dc.Options.DisableCacheDelete = false // 关闭缓存删除,默认false;如果打开,那么TagAsDeleted就什么操作都不做,直接返回

	// 3、其他设置
	// 标记删除的延迟时间,默认10秒,设置为3秒表示:被删除的key在3秒后才从redis中彻底清除
	dc.Options.Delay = time.Second * time.Duration(3)
	// 防穿透: 若fn返回空字符串,空结果在缓存中的缓存时间,默认60秒
	dc.Options.EmptyExpire = time.Second * time.Duration(120)
	// 防雪崩: 默认0.1,当前设置为0.1的话,如果设定为600的过期时间,那么过期时间会被设定为540s - 600s中间的一个随机数,避免数据出现同时到期
	dc.Options.RandomExpireAdjustment = 0.1 // 设置为默认或不设置就行

	/* 
	   锁相关参数,这里配置的默认值,没有特殊情况建议默认
     rockscache使用lua脚本一次性执行,执行过程中其他脚本或命令无法执行,
     并且使用hash存储,同时保存 key/value 与 key/lock
	 */
  // 更新缓存时分配的锁的过期时间。默认为 3s。注意设置为下级计算数据时间的最大值。
	dc.Options.LockExpire = time.Second * time.Duration(3)
	// 锁失败后的重试等待时间 100ms
	dc.Options.LockSleep = time.Millisecond * time.Duration(100)

	log.NewHelper(logger).Infow("kind", "rocksCache", "status", "enable")
	return dc
}

1-2、rockscache原理解读

1、参考(这个文章用的rockscache的版本有点低,参考一下就行):

https://xboom.github.io/2022/07/31/Microservices/微服务-缓存一致性/

2、lua脚本

使用脚本进行redis操作,lua的好处是一次性执行,执行过程其他脚本或命令无法执行(注意不确定参数)。

这里使用hash进行数据存储,同时保存 key/valuekey/lock

✅ 配置项演示

1、简单的get请求

FindCountById这个接口,使用Fetch2方法,传ctx。

数据库中的数据:

id count create_time update_time
1	100	2023-02-13 11:42:42	2023-02-13 11:42:42
2	200	2023-02-13 11:42:46	2023-02-13 11:42:46

一开始缓存中没有数据。

查询id为1的数据库中有的数据:

// 127.0.0.1:19000
{
  "id": 1
}

可以看到打印出来:查询数据库了~~

查看下缓存:

hgetall countCache1
1) "value"
2) "{\"id\":\"1\",\"count\":100,\"createTime\":\"2023-02-13T11:42:42+08:00\",\"updateTime\":\"2023-02-13T11:42:42+08:00\"}"

再查询一下,就不会打印查询数据库了~此时会从redis中查数据

看一下缓存的TTL:

ttl countCache1
(integer) 89

2、缓存穿透(查id不存在数据的写法)

1、演示一下:缓存穿透,db中没有数据的情况~ 会生成一个空值(key对应的是countValue3,value里面的值是空字符串) ttl是自己设置的,❗️特别注意一下,需要代码中做“无记录”特殊的处理——不要返回错误!返回空字符串!

dc.Options.EmptyExpire = time.Second * time.Duration(120)

业务代码的写法:

func (r *layoutRepo) FindCountById(ctx context.Context, id int64) (*biz.Count, error) {

	db := r.data.DB(ctx).Table(biz.CountTableName)
	cacheKey := fmt.Sprintf(countCacheFormatKey, id)

	value, errValue := r.data.rocksCache.Fetch2(ctx, cacheKey, time.Second*100, func() (string, error) {
		// 缓存中没有数据默认从数据库查
		fmt.Println("查数据库了~~~~~~~~~~~~~~~~~~~~~~~~")
		model := &biz.Count{}
		errFirst := db.Where("id = ?", id).First(model).Error
		// ❗️❗️ ❗️ 数据库中无记录,返回一个空字符串~~redis中会记录一个这个key对应空字符串数据的记录,防止缓存穿透!
		if errFirst == gorm.ErrRecordNotFound {
			return "", nil
		}

		if errFirst != nil {
			return "", errFirst
		}
		// Marshal
		ma, errMa := json.Marshal(model)
		if errMa != nil {
			return "", errMa
		}
		return convertor.ToString(ma), nil
	})

	if errValue != nil {
		return nil, errValue
	}

	ret := &biz.Count{}
	// value在数据库没有数据时返回空,这里得做空判断
	if value != "" {
		body, errBody := convertor.ToBytes(value)
		if errBody != nil {
			return nil, errBody
		}
		errUnmarshal := json.Unmarshal(body, ret)
		if errUnmarshal != nil {
			return nil, errUnmarshal
		}
	}

	return ret, nil
}

演示:发送一个id不存在的请求:

// 127.0.0.1:19000
{
  "id": 333
}

一开始查询了一下数据库,但是后面就不再从数据库中查数据了,可以看到缓存中有了相对应的key:

hgetall countCache333
1) "value"
2) ""

3、redis降级场景

需要设置参数:

dc.Options.DisableCacheRead = true   // 关闭缓存读,默认false;如果打开,那么Fetch就不从缓存读取数据,而是直接调用fn获取数据
dc.Options.DisableCacheDelete = true // 关闭缓存删除,默认false;如果打开,那么TagAsDeleted就什么操作都不做,直接返回

然后把docker中的redis关了,试试:

// redis关了
hgetall countCache333
Could not connect to Redis at 127.0.0.1:6379: Connection refused

发送下请求,可以看到,所有的查询都走了数据库~

4

标签:缓存,kratos,redis,42,介绍,rockscache,2023,id
From: https://www.cnblogs.com/paulwhw/p/17120966.html

相关文章

  • vue-day01——前端发展历史、vue的介绍及基本使用
    目录今日内容详细一、前端发展历史二、Vue的介绍与基本使用1.Vue简介2.Vue特点3.M-V-VM思想4.组件化开发、单页面开发5.版本选择6.引入方式7.简单使用8.补充今日内容详细......
  • 前端发展史 vue介绍 vue的快速使用
    上节回顾#1jwt源码分析-签发: 登录----》ObtainJSONWebToken--->post--->serializer.is_valid()--->走了校验---》正常登录逻辑可以拿到序列化类的validate中......
  • Mybatis13 - 缓存介绍
    介绍理解缓存的工作机制和缓存的用途。1、缓存机制介绍2、一级缓存和二级缓存①使用顺序查询的顺序是:先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的......
  • fiddler详细介绍
    csdn知名作者:极客小俊   的全网最强HTTP+Fiddler抓包实战教程干得不能再干(超级全面图文)得到了我的认可!!!链接在这:极客小俊......
  • java深拷贝和浅拷贝介绍
    浅拷贝概念  深拷贝概念@Data@Slf4jpublicclassSheepimplementsCloneable{privateStringname;privateintage;privateStringcolor;privateShe......
  • 编程基础与python介绍
    1、计算机内部存储数据的原理2、编程语言的发展史3、python解释器版本4、多版本的共存(重要)5、python的运行方式6、python的下载与安装7、路径8.环境变量 ......
  • 1 drf回顾 、2 前端发展历史、 3 vue介绍
    目录1drf回顾2前端发展历史3vue介绍1drf回顾#1drf入门规范 -前后端分离模式-前后端混合-postman-restful规范-drf:django的app#2序列化类......
  • [无聊/科普向] 一篇关于《原神》抽卡概率/期望计算的正经介绍
    最近学深度学习上手Python后想试试用MATLAB画图,于是随便找了个话题写写,文章本身没啥含金量(注:本文的正确性建立在目前广为流传的一份角色池与武器池单抽出货概率数据......
  • python中sys.argv模块的介绍
    1、所有命令行参数都可以通过模块中的sys.argv访问,其返回值是包含所有命令行参数的列表(list)。2、Python在执行程序时,从命令行中获取所有值,并将其存储在sys.argv列表中。实......
  • python canvas画布的介绍
    1、在画布上绘制对象,通常用create_xxxx,xxxx=对象类型。2、每次调用create_xxx,都会返回创建组件的ID,也可以用tag属性指定标签。3、通过调用canvas.move实现一次性动作。实例#......