Gone框架介绍18 - redis 分布式缓存 和 分布式锁

gone是可以高效开发Web服务的Golang依赖注入框架
github地址:https://github.com/gone-io/gone
文档地址:https://goner.fun/zh/
请帮忙在github上点个 ⭐️吧,这对我很重要 ;万分感谢!!

文章目录

  • 利用redis提供分布式锁和分布式缓存
    • 第一步:将redis相关Goner埋葬到Cemetery
    • 第二步:在配置文件中增加redis相关配置
    • 第三步,使用redis
      • 注入接口
      • 使用分布是缓存
      • 使用分布时锁
    • 上面例子完整代码

利用redis提供分布式锁和分布式缓存

在本文中,我们将分享在gone中如何使用分布式缓存和分布式锁,其中分布式锁中实现了一种较为自由的处理方式———“智能锁”,对一个处理函数进行上锁,函数执行中会周期性检测锁过期的剩余时间并自动给锁续期,函数执行完后会自动解锁。

第一步:将redis相关Goner埋葬到Cemetery

什么是 Goner?
什么是 埋葬?
什么是 Cemetery?
参考 Gone的核心概念

在Priest函数中增加_ = goner.RedisPriest(cemetery),如下:

func priest(cemetery gone.Cemetery) error {//使用 goner.RedisPriest 函数,将 redis 相关的Goner 埋葬到 Cemetery 中_ = goner.RedisPriest(cemetery)cemetery.Bury(&redisUser{})return nil
}

第二步:在配置文件中增加redis相关配置

创建配置文件 config/default.properties,内容如下:

# redis服务地址,格式为 `host:port`
redis.server=localhost:6379# redis服务密码,不配置默认为空
redis.password=

其中,redis服务地址需要改你能访问到的redis服务地址。

更多配置:

  • redis.max-idle:最大空闲链接数,不配置默认为2
  • redis.max-active:最大活跃链接数,不配置默认为10
  • redis.db:使用的db,不配置默认为0
  • redis.cache.prefix:key前缀,如果设置了,对redis的增删改查都会拼接该前缀,拼接方式${prefix}#${key};默认为空

关于配置文件,更多参考:通过内置Goners支持配置文件

第三步,使用redis

注入接口

在需要使用的结构体中注入 接口redis.redis.Cacheredis.Locker,他们的GonerId分别为:gone-redis-cachegone-redis-locker

type redisUser struct {gone.Flagcache  redis.Cache  `gone:"gone-redis-cache"`locker redis.Locker `gone:"gone-redis-locker"`
}

使用分布是缓存

请看下面代码中的注释:

func (r *redisUser) UseCache() {key := "gone-address"value := "https://github.com/gone-io/gone"//设置缓存err := r.cache.Put(key,            //第一个参数为 缓存的key,类型为 `string`value,          // 第二参数为 需要缓存的值,类型为any,可以是任意类型;传入的值会被编码为 `[]byte` 发往redis10*time.Second, // 第三个参数为 过期时间,类型为 `time.Duration`;省略,表示不设置过期时间)if err != nil {fmt.Printf("err:%v", err)return}//获取缓存var getValue stringerr = r.cache.Get(key,       //第一个参数为 缓存的key,类型为 `string`&getValue, //第二参数为指针,接收获取缓存的值,类型为any,可以是任意类型;从redis获取的值会被解码为传入的指针类型)if err != nil {fmt.Printf("err:%v", err)return}fmt.Printf("getValue:%v", getValue)
}

接口上的其他方法:

  • Remove(key string) (err error):用于删除redis某个key,支持通配符
  • Keys(key string) ([]string, error):使用前缀或者通配符查询存在哪些key,⚠️该方法慎用
  • Prefix() string:获取当前缓存配置的key前缀

使用分布时锁

  1. 锁定一段时间
func (r *redisUser) UseLock() {lockKey := "gone-lock-key"//尝试获取锁 并 锁定一段时间//返回的第一个参数为一个解锁的函数unlock, err := r.locker.TryLock(lockKey,        //第一个参数为 锁的key,类型为 `string`10*time.Second, //第二参数为 锁的过期时间,类型为 `time.Duration`)if err != nil {fmt.Printf("err:%v", err)return}//操作完后,需要解锁defer unlock()//获取锁成功后,可以进行业务操作//todo
}

这种方式,使用锁需要保证在锁定的时间内能够执行完所有操作,否则由于锁过期可能会导致问题。

  1. 锁定一个操作,操作没结束会自动给锁续期,操作结束自动解锁
func (r *redisUser) LockFunc() {lockKey := "gone-lock-key"err := r.locker.LockAndDo(lockKey, //第一个参数为 锁的key,类型为 `string`func() { //第二个参数为 需要执行的函数,类型为 `func()`,代表一个操作//获取锁成功后,可以进行业务操作//todoprintln("do some options")},100*time.Second, //第三个参数为 锁的过期时间,类型为 `time.Duration`;第一次加锁和后续锁续期都将使用该值5*time.Second,   //第四个参数为 锁续期的间隔时间,类型为 `time.Duration`;周期性检查所是否将过期,如果在下个周期内会过期则对锁续期)if err != nil {fmt.Printf("err:%v", err)}
}

这种方式比较智能,姑且将其称为“智能锁”吧!
推荐使用这种方式,可以无脑使用,降低使用的心智负担。

上面例子完整代码

例子的源代码可以在这里找到

package mainimport ("fmt""github.com/gone-io/gone""github.com/gone-io/gone/goner""github.com/gone-io/gone/goner/redis""time"
)func priest(cemetery gone.Cemetery) error {//使用 goner.RedisPriest 函数,将 redis 相关的Goner 埋葬到 Cemetery 中_ = goner.RedisPriest(cemetery)cemetery.Bury(&redisUser{})return nil
}type redisUser struct {gone.Flagcache  redis.Cache  `gone:"gone-redis-cache"`locker redis.Locker `gone:"gone-redis-locker"`
}func (r *redisUser) UseCache() {key := "gone-address"value := "https://github.com/gone-io/gone"//设置缓存err := r.cache.Put(key,            //第一个参数为 缓存的key,类型为 `string`value,          // 第二参数为 需要缓存的值,类型为any,可以是任意类型;传入的值会被编码为 `[]byte` 发往redis10*time.Second, // 第三个参数为 过期时间,类型为 `time.Duration`;省略,表示不设置过期时间)if err != nil {fmt.Printf("err:%v", err)return}//获取缓存var getValue stringerr = r.cache.Get(key,       //第一个参数为 缓存的key,类型为 `string`&getValue, //第二参数为指针,接收获取缓存的值,类型为any,可以是任意类型;从redis获取的值会被解码为传入的指针类型)if err != nil {fmt.Printf("err:%v", err)return}fmt.Printf("getValue:%v", getValue)
}func (r *redisUser) LockTime() {lockKey := "gone-lock-key"//尝试获取锁 并 锁定一段时间//返回的第一个参数为一个解锁的函数unlock, err := r.locker.TryLock(lockKey,        //第一个参数为 锁的key,类型为 `string`10*time.Second, //第二参数为 锁的过期时间,类型为 `time.Duration`)if err != nil {fmt.Printf("err:%v", err)return}//操作完后,需要解锁defer unlock()//获取锁成功后,可以进行业务操作//todo
}func (r *redisUser) LockFunc() {lockKey := "gone-lock-key"err := r.locker.LockAndDo(lockKey, //第一个参数为 锁的key,类型为 `string`func() { //第二个参数为 需要执行的函数,类型为 `func()`,代表一个操作//获取锁成功后,可以进行业务操作//todoprintln("do some options")},100*time.Second, //第三个参数为 锁的过期时间,类型为 `time.Duration`;第一次加锁和后续锁续期都将使用该值5*time.Second,   //第四个参数为 锁续期的间隔时间,类型为 `time.Duration`;周期性检查所是否将过期,如果在下个周期内会过期则对锁续期)if err != nil {fmt.Printf("err:%v", err)}
}func main() {gone.Prepare(priest).AfterStart(func(in struct {r *redisUser `gone:"*"`}) {in.r.UseCache()in.r.LockTime()}).Run()
}

上一篇:Gone框架介绍17 - 创建一个可运行在生产环境的Web项目
下一篇:Gone框架介绍19 -如何进行单元测试?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/13196.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python | Leetcode Python题解之第92题反转链表II

题目: 题解: class Solution:def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:# 设置 dummyNode 是这一类问题的一般做法dummy_node ListNode(-1)dummy_node.next headpre dummy_nodefor _ in range(left - 1):pre…

云计算第十八课

目录操作 移动 改名 批量改名,写脚本 mv [选项] … 源文件或目录… 目标文件或目录 单个文件 移动 或者改名 -f:强制覆盖,如果目标文件已经存在,则不询问,直接强制覆盖; -i:交互移动&#x…

零基础学Java第十四天之抽象类

抽象类和抽象类的深入 抽象类 1、理解 抽象类(Abstract Class)是面向对象编程中的一个重要概念,尤其在像Java、C#和C等编程语言中。抽象类是一种特殊的类,它不能被实例化(即不能创建抽象类的对象)&#x…

鼠标悬浮(hover)时显示提示框的效果

在Vue中,你可以使用多种方法来实现鼠标悬浮(hover)时显示提示框的效果。以下是一个简单的示例,它使用了Vue的指令(directive)和条件渲染(conditional rendering)来实现这个功能。 首…

关于FIFO Generator IP和XPM_FIFO在涉及位宽转换上的区别

在Xilinx FPGA中,要实现FIFO的功能时,大部分时候会使用两种方法: FIFO Generator IP核XPM_FIFO原语 FIFO Generator IP核的优点是有图形化界面,配置参数非常直观;缺点是参数一旦固定,想要更改的化就只能重…

一次tomcat闪退处理

双击tomcat目录下bin目录中startup.bat 在我的电脑上是一闪而过,不能正常地启动tomcat软件 以记事本打开startup.bat文件,在文件的结尾处加上pause 然后再双击该bat执行,此时窗口就不会关闭,并会将错误信息打印在提示框中 可能是…

英伟达发布 VILA 视觉语言模型,实现多图像推理、增强型上下文学习,性能超越 LLaVA-1.5

前言 近年来,大型语言模型 (LLM) 的发展取得了显著的成果,并逐渐应用于多模态领域,例如视觉语言模型 (VLM)。VLM 旨在将 LLM 的强大能力扩展到视觉领域,使其能够理解和处理图像和文本信息,并完成诸如视觉问答、图像描…

一看就会的AOP事务

文章目录 AOPAOP简介AOP简介和作用AOP的应用场景为什么要学习AOP AOP入门案例思路分析代码实现AOP中的核心概念 AOP工作流程AOP工作流程AOP核心概念在测试类中验证代理对象 AOP切入点表达式语法格式通配符书写技巧 AOP通知类型AOP通知分类AOP通知详解 AOP案例案例-测量业务层接…

Linux bc命令(bc指令)(基本计算器)(任意精度计算语言:支持浮点数运算、变量赋值和自定义函数等)

文章目录 bc命令文档英文中文 Linux bc 命令详解bc 命令的基本用法启动 bc 环境进行基本计算退出 bc bc 中的数学功能执行高级数学计算平方根和指数函数对数函数 处理精度问题 变量和数组变量赋值和使用数组的使用 创建和使用自定义函数 bc 命令的高级用法在脚本中使用 bc基本脚…

Google I/O 大会 | 精彩看点一览

作者 / 开发者关系和开源总监 Timothy Jordan 2024 年 Google I/O 大会于北京时间 5 月 15 日 1:00am 在加利福尼亚的山景城以 Google 主题演讲直播拉开序幕。随后,在北京时间 4:30am 举行开发者主题演讲。大家可前往回看 "Google 主题演讲" 以及 "开…

AIGC时代已至,你准备好抓住机遇了吗?

一、行业前景 AIGC,即人工智能生成内容,是近年来人工智能领域中发展迅猛的一个分支。随着大数据、云计算、机器学习等技术的不断进步,AIGC已经取得了显著的成果,并且在广告、游戏、自媒体、教育、电商等多个领域实现了广泛应用。…

AI写算法:支持向量机(SVM)

在Python中,我们可以使用scikit-learn库来实现支持向量机(SVM)。以下是一个简单的示例,演示如何使用scikit-learn的SVC类来训练一个SVM分类器,并使用它对一些数据进行预测。 python复制代码 # 导入必要的库 from skle…

图像中的attention及QKV机制解释

简单记录/推荐两篇博客,后续细化写一下: 图像中的各类 attention https://blog.csdn.net/weixin_44505185/article/details/127013204 Cross-attention的直观理解 首先理解,cross-attention 是两个不同向量间的相关计算,一般Q…

DolphinScheduler(海豚调度)- docker部署实战

1.官方文档 https://dolphinscheduler.apache.org/zh-cn/docs/3.2.1/guide/start/docker 2.docker环境安装 版本情况(这个地方踩了不少坑):docker-26.1.2,docker-compose-v2.11.0。 具体可使用我上传的安装包,一键安…

leetcode题目55

跳跃游戏 中等 给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。 示例 1…

MT3037 新月轩就餐

思路: 此题每道菜的价钱相同,想最小化付的钱即求最小区间长度可以满足“品尝到所有名厨手艺”。 使用双端队列存储元素,队尾不断向后遍历:头->尾 如果队头队尾,则队头往右移一格,直到区间不同元素数m…

Docker部署MaxKB详细步骤(window系统)

上面章节已经实现了ollama李现部署llama3,并实现了一些简单的问答,但是问答的界面是在命令提示符中,交互很不友好,也不方便局域网其他用户访问,所以这节用docker部署MaxKB实现网页访问llama3,首先电脑上需要…

分布式系统的一致性与共识算法(四)

Etcd与Raft算法 Raft保证读请求Linearizability的方法: 1.Leader把每次读请求作为一条日志记录,以日志复制的形式提交,并应用到状态机后,读取状态机中的数据返回(一次RTT、一次磁盘写)2.使用Leader Lease,保证整个集群只有一个L…

使用Flask-RESTful构建RESTful API

文章目录 安装Flask-RESTful导入模块和类创建一个资源类运行应用测试API总结 Flask是一个轻量级的Python web开发框架,而Flask-RESTful是一个基于Flask的扩展,专门用于构建RESTful API。它提供了一些帮助类和方法,使构建API变得更加简单和高效…

详细分析Vue3中的reactive(附Demo)

目录 1. 基本知识2. 用法3. Demo 1. 基本知识 reactive 是一个函数,用于将一个普通的 JavaScript 对象转换为响应式对象 当对象的属性发生变化时,Vue 会自动追踪这些变化,并触发相应的更新 Vue2没有,而Vue3中有,为啥…