首页 > 数据库 >golang 使用redis设置分布式锁 demo

golang 使用redis设置分布式锁 demo

时间:2023-09-24 17:45:12浏览次数:32  
标签:err demo redis golang ctx Lock go 分布式

内容来自对 chatgpt 的咨询

分布式锁是在多个节点上运行的应用程序中协调工作的一种常用方法,而Redis是实现分布式锁的流行选择。以下是使用Go语言和github.com/go-redis/redis库来设置Redis分布式锁的一个简单示例:

首先,确保你已经安装了该库:

go get -u github.com/go-redis/redis/v8

demo

然后,这是一个简单的Go代码,用于设置和释放Redis分布式锁:

package main

import (
	"context"
	"fmt"
	"time"

	"github.com/go-redis/redis/v8"
)

var ctx = context.Background()

func main() {
	rdb := redis.NewClient(&redis.Options{
		Addr: "localhost:6379", // 你的Redis地址
		DB:   0,                 // 使用默认DB
	})

	lockKey := "my-lock-key"
	lockValue := "my-unique-identifier" // 这应该是一个每次都唯一的值,例如,可以使用UUID
	lockDuration := 5 * time.Second     // 锁持续时间

	// 尝试设置锁
	ok, err := rdb.SetNX(ctx, lockKey, lockValue, lockDuration).Result()
	if err != nil {
		panic(err)
	}

	if ok {
		fmt.Println("Lock acquired!")

		// 你的业务逻辑

		// 释放锁
		val, err := rdb.Get(ctx, lockKey).Result()
		if err == nil && val == lockValue {
			_, err := rdb.Del(ctx, lockKey).Result()
			if err != nil {
				panic(err)
			}
			fmt.Println("Lock released!")
		}
	} else {
		fmt.Println("Could not acquire lock!")
	}
}

注意:

1、这是一个简单的实现,而在实际生产环境中,你可能需要添加一些额外的功能,如重试机制、锁超时检查等。

2、使用SetNX(Set if Not eXists)确保只有一个客户端可以获得锁。

3、为了确保安全性,释放锁之前要检查锁的值确实是你设置的值。这样可以防止错误地释放其他客户端的锁。

4、在大型分布式系统中,你可能还需要考虑使用像Redlock这样的更复杂的算法来确保锁的安全性和稳定性。

问:Redis 分布式锁过期时间怎么合理设置,长了可能影响性能,短了可能任务没执行完

方案一:保证过期时间足够长,大部分的任务都能执行完,任务执行完主动释放锁

方案二:设置一个PT99任务能执行完的过期时间,没执行完则使用守护对锁进行续期,

对于方案一的代码实现

守护进程定期检测锁是否还在,只要 chan没有被关闭,说明锁还在。
只要锁还在就说明任务还没执行完,那么重置过期时间,等待任务执行完主动释放锁。
问题:该程序的守护进程怎么判断任务是否执行完毕,答:任务执行完毕会主动释放锁,释放锁时会关闭守护进程的chan,这时守护线程就会关闭,就不再续期了。

type Lock struct {
	daemon chan interface{} // 看门狗
	client   *redis.Client  // redis 客户端
	ttl      time.Duration    // 过期时间
	key      string           // 锁key
}

func (l *Lock) Lock(ctx context.Context) error {
	// 尝试获取锁
	var value = "1"
	success, err := l.client.SetNX(l.key, value, l.ttl).Result()
	logs.CtxInfo(ctx, "[Lock] success is %+v err is %+v", success, err)
	if err != nil {
		return errors.New("获取分布式锁失败")
	}
	if !success {
		return errors.New("获取分布式锁失败")
	}
    
	// 加锁成功,启动守护进程进行锁续期
	go l.DaemonLock()
	return nil
}

func (l *Lock) DaemonLock() { // 锁续期
    ticker := time.NewTicker(l.ttl / 2)
    defer ticker.Stop()
    for {
        select {
            case <-ticker.C:
            // 延长锁的过期时间
            ok, err := l.client.Expire(l.key, l.ttl).Result()
            // 异常或锁已经不存在则不再续期
            if err != nil || !ok {
                return
            }
            case <-l.daemon:
            // 已经解锁
            return
        }
    }
}

func (l *Lock) Unlock(ctx context.Context) error {
	// 关闭看门狗
	close(l.daemon)
	err := l.client.Del(l.key).Err()
	if err != nil {
		logs.CtxError(ctx, "Unlock err=%s", err.Error())
		return err
	}
	return err
}

DaemonLock 会在 l.daemon 这个通道被关闭或者在续约锁失败时退出。

这是因为当一个 Go 语言的通道被关闭后,尝试从这个通道中读取数据将会立即返回一个与通道类型相对应的零值,并且第二个返回值(一个布尔值)会被设为 false。select 语句会不断地尝试从 l.daemon 通道中读取值,如果通道被关闭,select 就会立即从对应的 case 中返回。

标签:err,demo,redis,golang,ctx,Lock,go,分布式
From: https://www.cnblogs.com/hi3254014978/p/17726302.html

相关文章

  • golang 对字符串进行base64编解码、md5 编码
    内容来自对chagpt的咨询一、对字符串进行base64编解码base64编码要在Go语言中对字符串进行base64编码,你可以使用标准库中的encoding/base64包。以下是一个简单的示例:packagemainimport( "encoding/base64" "fmt")funcmain(){ data:="Hello,World!" enc......
  • Redis搭建集群架构
    使用docker搭建6.x版本以后的镜像docker支持部署集群模式,由于Redis要求集群至少要有三个主节点,因此本次测试搭建了三主三从的Redis集群。不基于Host网络模式配置docker-compose.yml文件version:"3"networks:redis-cluster:driver:bridgeipam:......
  • golang 把内容写到 csv 文件或者 xlsx 文件里
    内容来自对chatgpt的咨询csv格式csv格式的文件使用wps或者office打开后是一个excel表格的形式,很容易看到表格里的数据。csv格式跟markdown格式有点像,只需要按照固定的语法放置文本,保存后,用对应的渲染软件打开,就能得到想要的效果。比如下面这段json,用文本编辑器......
  • 从一个golang 员工emp数组中,找到其中name相同的元素,把结果放到一个新数组里,代码实现
    内容来自对chatgpt的咨询为了找到具有相同名称的员工,并将结果放入一个新的数组中,我们可以首先使用一个映射(map)来存储每个名称及其出现的次数。然后,我们可以遍历原始数组并使用映射来判断是否有重复的名称。以下是一个示例代码,演示如何实现这一目标:packagemainimport( ......
  • Redis 命令工具
    ---Redis命令工具---redis-serverRedis服务器启动命令redis-clishutdown停止服务redis-benchmark:性能测试工具,用于检测Redis在本机的运行效率redis-check-aof:修复有问题的AOF持久化文件redis-check-rdb:修复有问题的RDB持久化文件redis-cli:Redis客户端命令行......
  • 深入探讨Spring Boot中的Redis缓存
    介绍Redis是一种高性能的内存数据库,常用于缓存和消息队列等场景。在SpringBoot中,我们可以通过集成Redis来实现缓存功能。本文将深入探讨SpringBoot中的Redis缓存。集成Redis在SpringBoot中,我们可以通过添加以下依赖来集成Redis:<dependency><groupId>org.springframewor......
  • Redis搭建哨兵模式架构
    使用Docker安装因为配置太复杂,所以这里我们使用dockercompose来一键部署不使用内部网络搭建编写redis主从docker-compose.ymlversion:'3'services:master:image:rediscontainer_name:redis-masterrestart:alwayscommand:redis-server--requi......
  • python生成图片验证码的demo
    下面是一个使用Python生成图片验证码的简单示例:fromPILimportImage,ImageDraw,ImageFontimportrandomdefgenerate_captcha(text,width,height,font_path,font_size):#创建一个空白图片image=Image.new('RGB',(width,height),(255,255,255))dr......
  • Redis7 数据持久化RDB
    一、概述1、官网介绍2、是什么在指定时间间隔,执行数据集的时间点快照实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照。这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保证。这个快照文件就称为RDB文件(dump.rdb),其中,R......
  • Redis 下载和安装(Windows)教程
    下载虽然Redis官方网站没有提供Windows版的安装包,但可以通过GitHub来下载Windows版Redis安装包。下载地址:https://github.com/tporadowski/redis/releases打开上述的下载链接,Redis支持32位和64位的Window系统,如图所示:下载完成后,解压压缩包,您会看到如下图......