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.Flag

	cache  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` 发往redis
		10*time.Second, // 第三个参数为 过期时间,类型为 `time.Duration`;省略,表示不设置过期时间
	)

	if err != nil {
		fmt.Printf("err:%v", err)
		return
	}

	//获取缓存
	var getValue string
	err = 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()`,代表一个操作
			//获取锁成功后,可以进行业务操作
			//todo
			println("do some options")
		},
		100*time.Second, //第三个参数为 锁的过期时间,类型为 `time.Duration`;第一次加锁和后续锁续期都将使用该值
		5*time.Second,   //第四个参数为 锁续期的间隔时间,类型为 `time.Duration`;周期性检查所是否将过期,如果在下个周期内会过期则对锁续期
	)
	if err != nil {
		fmt.Printf("err:%v", err)
	}
}

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

上面例子完整代码

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

package main

import (
	"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.Flag

	cache  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` 发往redis
		10*time.Second, // 第三个参数为 过期时间,类型为 `time.Duration`;省略,表示不设置过期时间
	)

	if err != nil {
		fmt.Printf("err:%v", err)
		return
	}

	//获取缓存
	var getValue string
	err = 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()`,代表一个操作
			//获取锁成功后,可以进行业务操作
			//todo
			println("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 -如何进行单元测试?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Media Encoder 2024 for Mac:专业的音视频编码神器

Media Encoder 2024 for Mac,作为Mac用户的专业音视频编码工具,凭借其强大的功能和用户友好的界面,深受专业人士的喜爱。它支持将各种格式的音视频素材转换为多种流行格式,如MP4、MOV、AVI等,满足不同的播放和发布需求…

python:functools.partial和functools.wraps使用

python:functools.partial和functools.wraps使用 1 前言 python内置的functools模块,提供了一些非常好用的类或者方法,其中functools.partial和functools.wraps的使用频率较高,本文将针对其分析使用。 2 使用 2.1 functools.p…

No module named ‘sklearn.metrics.ranking‘ 解决方法

错误代码 from sklearn.metrics.classification import * from sklearn.metrics.ranking import * 错误原因 sklearn这个文件夹下的_classification和_ranking前面有下划线! 解决方法 第一步:找到sklearn位置,可以打开命令行输入 pip sh…

ASTM通信协议校验和计算方法

Lis通信接口开发 <STX> FN <Frame> <ETB>or<ETX> <CS><CR> <LF> 其中&#xff1a; <STX>&#xff1a;起始帧头&#xff08;0x02&#xff09; FN&#xff1a;帧号&#xff08;范围0&#xff5e;7&#xff0c;1&#xff5e;7完…

软考--试题六--抽象工厂模式(Abstract Factory)

抽象工厂模式(Abstract Factory) 意图 提供一个创建一系列相关或相互依赖对象的接口&#xff0c;而无须指定他们具体的类 结构 适用性 1、一个系统要独立于它的产品的创建、组合和表示时 2、一个系统要由多个产品系统中的一个来配置时 3、当要强调一系列相关的产品对象的设…

问界新M5交付,「975」组合站稳中国豪华智电定位

‍作者 |老缅 编辑 |德新 5月15日&#xff0c;问界新M5已正式开启全国用户交付。从网传图片可以看到&#xff0c;华为余承东以及赛力斯AITO问界BU总裁何利扬亲自出席了首批交车仪式。 4月23日&#xff0c;在不到1个月前&#xff0c;新M5发布。新M5共推出三款车型&#xff1a; …

基于ASN.1的RSA算法公私钥存储格式解读

1.概述 RFC5958主要定义非对称密钥的封装语法&#xff0c;RFC5958用于替代RFC5208。非对称算法会涉及到1对公私钥&#xff0c;例如按照RSA算法&#xff0c;公钥是n和e&#xff0c;私钥是d和n。当需要将公私钥保存到文件时&#xff0c;需按照一定的格式保存。本文主要定义公私钥…

leetcode刷题(6):二叉树的使用

文章目录 104. 二叉树的最大深度解题思路c 实现 94. 二叉树的中序遍历解题思路c 实现 101. 对称二叉树解题思路c 实现 96. 不同的二叉搜索树解题思路c 实现 102. 二叉树的层序遍历解题思路c 实现 104. 二叉树的最大深度 题目: 给定一个二叉树 root &#xff0c;返回其最大深度…

一文读懂deepSpeed:深度学习训练的并行化

引言 在深度学习领域&#xff0c;模型训练的过程不仅资源密集&#xff0c;而且技术复杂。近年来&#xff0c;随着模型规模和数据量的不断增长&#xff0c;深度学习训练面临着越来越多的挑战。这些挑战主要体现在计算资源的需求、训练效率、模型复杂度以及内存管理等多个方面。…

postgres 修改系统时间测试

修改系统时间 [rootmmsql01 ~]# date 2024年 05月 16日 星期四 13:07:02 CST [rootmmsql01 ~]# timedatectl set-time "2024-05-16 13:30:00" [rootmmsql01 ~]# date 2024年 05月 16日 星期四 13:30:03 CST [rootmmsql01 ~]# timedatectl set-time "2024-05-16…

基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统

1 基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统 文章目录 1 基于QEMU-aarch64学习UEFI(EDK2)-2安装操作系统1.1 二、基于qemu固件安装操作系统1.1.1 1、virt-manager安装1.1.2 2、创建虚拟机1.1.2.1 Ubuntu系统开机等待时间长问题解决 1.1.3 3、virt-manager日常使用1.1.4 4、…

GAN实例基于神经网络

目录 1.前言 2.实验 1.前言 需要了解GAN的原理查看对抗生成网络&#xff08;GAN&#xff09;&#xff0c;DCGAN原理。 采用手写数字识别数据集 2.实验 import argparse import os import numpy as np import mathimport torchvision.transforms as transforms from torchvi…

怎么把照片变小做头像?多种方法教你图片改尺寸

现在在社交媒体平台或者是社交软件上&#xff0c;我们经常会去更改头像来展示自己&#xff0c;但是有时候我们拍摄的照片太大无法直接用作头像&#xff0c;这时候就需要去修改图片尺寸&#xff0c;将图片改大小到合适的数值才能使用&#xff0c;那么如何快速的将图片改大小呢&a…

在UBuntu上安装QT环境

一、UBuntu环境 二、官网下载QT https://download.qt.io/archive/qt/ 安装所需选择版本下载&#xff0c;可以现在windows下载在复制进去 三、安装QT 1、复制到ubuntu 2、打开终端&#xff0c;改变刚下载文件的权限 权限代号 r&#xff1a;读取权限&#xff0c;数字代号为 “…

手机图片恢复不求人:手动找回丢失的照片!

无论是外出旅行、聚会还是日常点滴&#xff0c;我们总是习惯用手机记录下来&#xff0c;让美好的瞬间定格在一张张照片中。然而&#xff0c;有时因为误删、清空缓存或是更换手机&#xff0c;那些珍贵的照片突然消失了。手机图片恢复有什么简单易行、容易上手的方法吗&#xff1…

MySQL创建存储过程函数(2)

DDL CREATE TABLE student (id int(11) NOT NULL AUTO_INCREMENT COMMENT 学号,createDate datetime DEFAULT NULL,userName varchar(20) DEFAULT NULL,pwd varchar(36) DEFAULT NULL,phone varchar(11) DEFAULT NULL,age tinyint(3) DEFAULT NULL,sex char(2) DEFAULT NULL,i…

上海初中生古诗文大会倒计时4个月:单选题真题示例和独家解析

现在距离2024年初中生古诗文大会还有4个多月时间&#xff0c;备考要趁早&#xff0c;因为知识点还是相对比较多的。这些知识点对于初中语文的学习也是很有帮助的。 今天我们继续来看10道选择题真题和详细解析&#xff0c;以下题目截取自我独家制作的在线真题集&#xff0c;都是…

教你五行代码实现大批量文件重命名

问题背景 文件夹里的大量文件&#xff0c;命名很乱&#xff0c;并且要重新命名为固定长度顺序的文件很麻烦。这里采用5行python实现大批量文件按要求统一命名。 现有文件夹列表 tulips 代码实现 main.py import os path rtulips/ for num, file in enumerate(os.listdir(…

狙击策略专用术语以及含义,WeTrade3秒讲解

想必各位交易高手对狙击策略不会陌生吧!但你想必不知道狙击策略的开发者为了推广狙击策略&#xff0c;在狙击策略基础的经典技术分析理论引入了自己的术语。今天WeTrade众汇和各位投资者继续了解狙击策略专用术语以及含义。 一.BL 银行级别(BL)是前一日线收盘的级别。时间是格…

央视的AI动画《AI我中华》宣传视频,原来用AI工具Stable Diffusion制作,竟然这么简单?

大家好&#xff0c;我是向阳。 前段时间&#xff0c;央视的《爱我中华》AI宣传短片火爆全网&#xff0c;有一个穿越转场效果非常惊艳&#xff01;先来回顾回顾&#xff1a; 今天就先来详细讲解&#xff0c;如何利用Stable Diffusion制作这样的穿越转场视频。 如你还没有安装St…