.Netcore 使用CSRedis Lock分布式加锁原理

news/2024/5/20 0:33:38 标签: .netcore, 分布式, redis

·引用地址:.Netcore 使用CSRedis Lock分布式加锁原理_csredisclientlock_FameLee-的博客-CSDN博客

订阅专栏
1.//使用方法
 
  using (var Lock = RedisHelper.Lock("锁名", "过期时间"))//返回CSRedisClientLock方法
            {
                if (Lock == null)
                {
                    return new Response<bool>().Fail("获取分布式锁失败");
                }
              //业务代码
            }//using结束默认调用CSRedisClientLock的Dispose方法,释放锁
2.//源代码分析
 
    public CSRedisClientLock Lock(string name, int timeoutSeconds, bool autoDelay = true)
        {
            name = $"CSRedisClientLock:{name}";
            var startTime = DateTime.Now;
            while (DateTime.Now.Subtract(startTime).TotalSeconds < timeoutSeconds)//通多过期时间循环去等待加锁
            {
                var value = Guid.NewGuid().ToString();
                if (this.Set(name, value, timeoutSeconds, RedisExistence.Nx) == true)//通过Redis Setnx设置锁也就是redis的 key value
                {
                    double refreshSeconds = (double)timeoutSeconds / 2.0;
                    return new CSRedisClientLock(this, name, value, timeoutSeconds, refreshSeconds, autoDelay);//返回CSRedisClientLock类
                }
                Thread.CurrentThread.Join(3);//加锁失败阻塞当前线程
            }
            return null;
        }
        
    public bool Set(string key, object value, TimeSpan expire, RedisExistence? exists = null)//通过Redis Setnx设置锁成功返回true失败返回false
        {
            object redisValule = this.SerializeRedisValueInternal(value);
            if (expire <= TimeSpan.Zero && exists == null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule)) == "OK";
            if (expire <= TimeSpan.Zero && exists != null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, null, exists)) == "OK";
            if (expire > TimeSpan.Zero && exists == null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, expire, null)) == "OK";
            if (expire > TimeSpan.Zero && exists != null) return ExecuteScalar(key, (c, k) => c.Value.Set(k, redisValule, expire, exists)) == "OK";
            return false;
        }
        
    private static RedisStatus.Nullable Set(string key, object value, int? expirationSeconds = null, long? expirationMilliseconds = null, RedisExistence? exists = null)
        {
            var args = new List<object> { key, value };
            if (expirationSeconds != null)
                args.AddRange(new[] { "EX", expirationSeconds.ToString() });
            if (expirationMilliseconds != null)
                args.AddRange(new[] { "PX", expirationMilliseconds.ToString() });
            if (exists != null)
                args.AddRange(new[] { exists.ToString().ToUpperInvariant() });// 通过Setnx设置锁
            return new RedisStatus.Nullable("SET", args.ToArray());
        }
        
public class CSRedisClientLock : IDisposable
    {
 
        CSRedisClient _client;
        string _name;
        string _value;
        int _timeoutSeconds;
        Timer _autoDelayTimer;
 
        public CSRedisClientLock(CSRedisClient rds, string name, string value, int timeoutSeconds, double refreshSeconds, bool autoDelay)
        {
            _client = rds;
            _name = name;
            _value = value;
            _timeoutSeconds = timeoutSeconds;
            if (autoDelay)
            {
                var refreshMilli = (int)(refreshSeconds * 1000);
                var timeoutMilli = timeoutSeconds * 1000;
                _autoDelayTimer = new Timer(state2 => Refresh(timeoutMilli), null, refreshMilli, refreshMilli);
            }
        }
 
 
        /// <summary>
        /// 释放分布式
        /// </summary>
        /// <returns>成功/失败</returns>
        public bool Unlock()
        {
            _autoDelayTimer?.Dispose();
            return _client.Eval(@"local gva = redis.call('GET', KEYS[1])
if gva == ARGV[1] then
  redis.call('DEL', KEYS[1])
  return 1
end
return 0", _name, _value)?.ToString() == "1";
        }
 
        public void Dispose() => this.Unlock();
    }
CSRedis GitHub地址

3.分布式加锁流程
1.通过Redis Setnx加锁并设置过期时间。
2.如果锁不存在就加锁。
3.如果锁存在就通过join阻塞线程,循环等待加锁直至过期时间结束。
4.加锁成功后执行业务并释放锁。
5.加锁失败返回错误。
————————————————
版权声明:本文为CSDN博主「FameLee-」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_40138785/article/details/122124460


http://www.niftyadmin.cn/n/1009755.html

相关文章

【Linux】—— 进程的环境变量

序言&#xff1a; 在上期我们已经对进程PCB以及进程状态进行了详细的解释说明。今天&#xff0c;我将带领大家学习的是关于进程的环境变量的问题。 目录 &#xff08;一&#xff09;孤儿进程 1、基本介绍 2、代码演示 &#xff08;二&#xff09;环境变量 1、基本概念 2…

CVE-2022-31325

文章目录 CVE-2022-30887一、漏洞介绍二、渗透步骤1、打开网站2、查找注入点3、截取数据包4、SQL注入&#xff08;1&#xff09;、探测数据库&#xff08;2&#xff09;、探测数据表&#xff08;3&#xff09;、探测列名&#xff08;4&#xff09;、查看flag值 CVE-2022-30887 …

自定义类创建数组的赋值;并回复:窗体图片时间

缘由https://bbs.csdn.net/topics/392551630 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms;…

大数据Doris(五十四):BACKUP数据备份原理和语法

文章目录 BACKUP数据备份原理和语法 一、BACKUP数据备份原理 1、快照及快照上传 2、元数据准备及上传 二、BACKUP数据备份语法 BACKUP数据备份原理和语法 通过Doris数据导出的各种方式我们可以将Doris中的数据进行备份&#xff0c;除了export方式之外&#xff0c;Doris 还…

Echarts X轴label标签文本和刻度线对齐显示,而不是呈现在两个刻度线之间

如下图所示X轴标签文本Mon位于两个刻度线中间&#xff1a; 想要的效果是如下图&#xff0c;刻度线正下方是标签文本Mon&#xff1a; 只需要在xAxis中添加axisTick的alignWithLabel属性&#xff0c;属性值设为true即可&#xff1a; option {xAxis: {type: category,axisTick: …

java 自带的定时器的使用

1、在启动类上加上EnableScheduling 即在这个包下&#xff1a;org.springframework.scheduling.annotation.EnableScheduling 2、将设定为任务的类定义为Component 3、将设定为任务的类的方法上加上Scheduled 2/3的代码如下&#xff1a; Component public class TestTask {/…

(模拟) 657. 机器人能否返回原点 ——【Leetcode每日一题】

❓ 657. 机器人能否返回原点 难度&#xff1a;简单 在二维平面上&#xff0c;有一个机器人从原点 (0, 0) 开始。给出它的移动顺序&#xff0c;判断这个机器人在完成移动后是否在 (0, 0) 处结束。 移动顺序由字符串 moves 表示。字符 move[i] 表示其第 i 次移动。机器人的有效…

git 取消上一次提交

目录 方法1&#xff1a;使用 Git reset 方法2&#xff1a;使用 Git revert 方法3&#xff1a;使用 Git checkout 如果你需要取消上一次的 Git 提交&#xff0c;有几个不同的方法可以实现。其中包括撤消提交、提交到新的分支、使用 Git 回滚等等。 下面介绍三种方法&#xf…