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

文章介绍了如何使用CSRedis库创建分布式锁,通过RedisSetnx设置带过期时间的锁,循环等待加锁直至超时,以及加锁成功后的业务处理和自动释放锁的机制。
摘要由CSDN通过智能技术生成

引用地址:https://blog.csdn.net/qq_40138785/article/details/122124460   

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值