如何使用 Redis 实现分布式锁

开发
在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问。现在公司都是流行分布式架构,在分布式环境下,如何保证不同节点的线程同步执行呢?

在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问。现在公司都是流行分布式架构,在分布式环境下,如何保证不同节点的线程同步执行呢?

实际上,对于分布式场景,我们可以使用分布式锁,它是控制分布式系统之间互斥访问共享资源的一种方式。对于每个锁,最好有一个唯一id,保证不会错误解锁。(例如 :A锁与B锁的key相同,在A锁过期的一瞬间,B锁进行解锁,若不校验锁id,会导致A锁被解锁);Redis提供了SETNX(set if not exists),仅在key不存在时插入value;Redis在2.6.12版本提供了SET函数的重载,支持仅在key不存在时插入带有过期时间的value;虽然Redis没有提供仅在value相同时删除的命令,但是在2.6.0版本提供了EXAL用于执行脚本,通过该脚本可以;仅在value相同时删除这一功能。

下面介绍实现分布式锁。

引入依赖

using ServiceStack.Redis;

锁实现过程

   private static readonly string ScriptSetIfAbsent = "return redis.call('SET',KEYS[1],ARGV[1],'EX',ARGV[2],'NX')";

        private static readonly string ScriptDeleteIfEqualValue = @"if redis.call('GET',KEYS[1]) == ARGV[1] then
        return redis.call('DEL',KEYS[1])
        else
        return 'FALSE'
        end";
  /// <summary>
        /// 加锁
        /// </summary>
        /// <param name="key">锁key</param>
        /// <param name="lockToken">锁令牌,用于释放锁</param>
        /// <param name="lockExpirySeconds">锁自动超时时间(秒)</param>
        /// <param name="waitLockSeconds">等待锁时间(秒)</param>
        /// <returns>加锁成功</returns>
        public bool Lock(string key, out string lockToken, int lockExpirySeconds = 10, double waitLockSeconds = 0)
        {
            int waitIntervalMs = 1000;
            string lockKey = GetLockKey(key);
            DateTime begin = DateTime.Now;
            string uuid = Guid.NewGuid().ToString();

            //循环获取取锁
            while (true)
            {
                string result;
                using (var client = GetNativeClient())
                {
                    //返回SET操作结果,为OK时成功
                    result = client.EvalStr(ScriptSetIfAbsent, 1,
                        System.Text.Encoding.UTF8.GetBytes(lockKey),
                        System.Text.Encoding.UTF8.GetBytes(uuid),
                        System.Text.Encoding.UTF8.GetBytes(lockExpirySeconds.ToString()));
                }

                if (result == "OK")
                {
                    lockToken = uuid;
                    return true;
                }

                //超过等待时间,则不再等待
                if ((DateTime.Now - begin).TotalSeconds >= waitLockSeconds) break;
                Thread.Sleep(waitIntervalMs);
            }
            lockToken = null;
            return false;
        }
   /// <summary>
        /// 释放锁,执行完代码以后调用
        /// </summary>
        /// <param name="key">锁Key</param>
        /// <param name="lockToken">锁令牌</param>
        /// <returns>释放锁成功</returns>
        public bool DelLock(string key, string lockToken)
        {
            if (string.IsNullOrWhiteSpace(lockToken))
            {
                throw new Exception("参数lockToken不能为空");
            }

            string lockKey = GetLockKey(key);
            using (var client = GetNativeClient())
            {
                //返回删除的行数,为1时成功
                string result = client.EvalStr(ScriptDeleteIfEqualValue, 1,
                    System.Text.Encoding.UTF8.GetBytes(lockKey),
                    System.Text.Encoding.UTF8.GetBytes(lockToken));
                return result == "1";
            }
        }

锁使用过程

   if (RedisManager.Lock(key, out tokenLock))
            {
                try
                {
                    IRedisClient rdsclient = null;
                    try
                    {
                     
                    }
                    finally
                    {
                        rdsclient?.Dispose();
                    }
                }
                finally
                {
                    RedisManager.DelLock(key, tokenLock);
                }
            }
责任编辑:赵宁宁 来源: conan
相关推荐

2024-04-01 05:10:00

Redis数据库分布式锁

2023-08-21 19:10:34

Redis分布式

2024-01-02 13:15:00

分布式锁RedissonRedis

2022-01-06 10:58:07

Redis数据分布式锁

2019-02-26 09:51:52

分布式锁RedisZookeeper

2019-06-19 15:40:06

分布式锁RedisJava

2022-08-11 18:27:50

面试Redis分布式锁

2021-11-01 12:25:56

Redis分布式

2020-07-15 16:50:57

Spring BootRedisJava

2020-07-30 09:35:09

Redis分布式锁数据库

2023-03-01 08:07:51

2023-01-13 07:39:07

2019-12-25 14:35:33

分布式架构系统

2023-10-11 09:37:54

Redis分布式系统

2024-02-20 09:50:02

Redis分布式

2021-10-25 10:21:59

ZK分布式锁ZooKeeper

2022-09-19 08:17:09

Redis分布式

2020-11-16 12:55:41

Redis分布式锁Zookeeper

2015-08-19 15:45:33

2022-03-04 09:54:04

Redis分布式锁脚本
点赞
收藏

51CTO技术栈公众号