首页 > 数据库 >Redis分布式锁的扩展方法

Redis分布式锁的扩展方法

时间:2023-12-15 16:57:50浏览次数:39  
标签:Console Redis 扩展 csredis 线程 key var 秒杀 分布式

 

分布式锁代码

#region 秒杀业务测试
        private static readonly string redisConnectionStr = "127.0.0.1:6379,connectTimeout=5000,allowAdmin=false,defaultDatabase=1";
        /// <summary>
        /// 秒杀业务
        /// </summary>
        private static void TestSeckillDemo()
        {
            //模拟线程数
            var thredNumber = 20;
            //秒杀库存数
            var stockNumber = 3;

            //秒杀成功队列key
            var key = "order_queue";
            //分布式锁key
            var nxKey = "orderNX";

            var csredis = new CSRedisClient(redisConnectionStr);
            csredis.Del(key);
            var isEnd = false;

            // 创建秒杀执行信号量集合
            List<Task> taskList = new List<Task>();
            // 添加计时器
            Stopwatch stopwatch = new Stopwatch();
            // 开启
            stopwatch.Start();
            for (int i = 0; i < thredNumber; i++)
            {
                int number = i;
                taskList.Add(Task.Run(() =>
                {
                    Thread.Sleep(50);

                    if (isEnd)
                    {
                        Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId} - 用户{number} 秒杀失败,抢完了。");
                    }

                    //设置客户端的标识,用于加锁解锁
                    var nxSelfMarkvalue = $"thred{Thread.CurrentThread.ManagedThreadId}_user{number}";
                    //当前线程用户加锁
                    var setnxResult = csredis.RedisLock(nxKey, nxSelfMarkvalue, 1000);
                    if (setnxResult)
                    {
                        var len = csredis.LLen(key);//获取列表长度
                        //成功的队列长度>=库存 (库存不足)
                        if (len >= stockNumber)
                        {
                            isEnd = true;
                            stopwatch.Stop();
                            Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId} - 用户{number} 秒杀失败,抢完了。");
                            //其实库存不足了,也不用解锁了。如果这里再做解锁操作,其他线程会出现再次加锁,但是返回的还是库存不足。加不加都行
                        }
                        else
                        {
                            var value = $"线程{Thread.CurrentThread.ManagedThreadId}-用户{number}";
                            csredis.LPush(key, value);//名单添加到成功队列
                            //当前线程用户解锁 (nxSelfMarkvalue,防止误解锁)
                            csredis.RedisUnLock(nxKey, nxSelfMarkvalue);
                            Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId} - 用户{number} 秒杀成功。");
                        }
                    }
                    else
                    {
                        Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId} - 用户{number} 系统繁忙,请稍后再试。 秒杀失败。");
                    }
                }));
            }
            // 等待所有秒杀列表中任务结束
            Task.WaitAll(taskList.ToArray());
            var lenALL = csredis.LLen(key);
            Console.WriteLine($"\r\n秒杀成功人数:{lenALL} 人,用时:{stopwatch.ElapsedMilliseconds} 毫秒.");
            Console.WriteLine($"\r\n是否超售:{(lenALL > stockNumber ? "是" : "否")}");
            Console.WriteLine("\r\n秒杀成功人员名单:");
            for (int i = 0; i < stockNumber; i++)
            {
                Console.WriteLine(csredis.RPop(key));
            }
        }
        #endregion
View Code

 

 

redis的扩展方法,一个加锁一个解锁的操作

/// <summary>
    /// Redis分布式锁
    /// </summary>
    public static class RedisDistributedLockExtension
    {

        #region 推荐使用
        /// <summary>
        /// 加锁毫秒级
        /// </summary>
        /// <param name="client">redis客户端连接</param>
        /// <param name="key">锁key</param>
        /// <param name="value">锁值</param>
        /// <param name="expireMilliSeconds">缓存时间 单位/毫秒 默认1000毫秒</param>
        /// <returns></returns>
        public static bool RedisLock(this CSRedisClient client, string key, object value, int expireMilliSeconds = 1000)
        {
            var script = @"local isNX = redis.call('SETNX', KEYS[1], ARGV[1])
                           if isNX == 1 then
                               redis.call('PEXPIRE', KEYS[1], ARGV[2])
                               return 1
                           end
                           return 0";

            return client.Eval(script, key, value, expireMilliSeconds)?.ToString() == "1";
        }

        /// <summary>
        /// 解锁
        /// </summary>
        /// <param name="client">redis客户端连接</param>
        /// <param name="key">锁key</param>
        /// <param name="selfMark">对应加锁客户端标识</param>
        /// <returns></returns>
        public static bool RedisUnLock(this CSRedisClient client, string key, string selfMark)
        {
            var script = @"local getLock = redis.call('GET', KEYS[1])
                            if getLock == ARGV[1] then
                              redis.call('DEL', KEYS[1])
                              return 1
                            end
                            return 0";

            return client.Eval(script, key, selfMark)?.ToString() == "1";
        }

        #endregion

    }
View Code


原文链接:https://blog.csdn.net/qq_39788123/article/details/124500222

标签:Console,Redis,扩展,csredis,线程,key,var,秒杀,分布式
From: https://www.cnblogs.com/love201314/p/17903677.html

相关文章

  • redis
    开启redis进程  redis-serverredis.windows.confredis对字符串的常用命令set 设置   get 获取  del  删除mset   mget设置获取多个key/valincr  incrby  decr   decrby    加/减setnx   msetnx   设置新的key/val   key必须是原来不存......
  • Helm Chart 部署 Redis 的完美指南
    目录一、Helm介绍二、安装Helm三、配置Helm的repository四、部署chart(以部署redis为例)1.搜索chart2.拉取chart3.修改values.yaml的一些配置(简单演示一下基本的配置)4.启动chart5.升级和回滚a.升级b.回滚一、Helm介绍Helm是一个Kubernetes的包管理工具,就像Linux下的包管......
  • hash长度扩展攻击
    hash长度扩展攻击就是针对允许包含额外信息的加密散列函数的攻击手段允许包含额外信息就是用户可用控制要加密的内容一般情况是:知道密钥长度知道密钥与某字符串拼接后的经过加密的hash值知道一部分要加密的内容要加密内容的不知道部分是用户输入的值用户需要传入一个hash......
  • redis未授权
    redis未授权搭建环境ubuntu安装并启动redis服务wgethttp://download.redis.io/releases/redis-3.2.11.tar.gz#下载压缩包tarxzfredis-3.2.11.tar.gz#解压cdredis-3.2.11#进入目录make#编译执行cdsrccpredis-server/usr/bin/cpredis-cli/usr/bin/#把上面两......
  • Kafka 分布式消息系统
    文章目录消息中间件对比Kafka概述kafka安装和配置kafka入门生产者发送消息消费者接收消息Kafka高可用设计集群备份机制(Replication)备份机制(Replication)-同步方式kafka生产者详解同步发送异步发送参数详解(ack)参数详解(retries)参数详解-消息压缩kafka消费者详解消费者组消息有......
  • Java-Redis是如何保证高可用的?
    Java-Redis是如何保证高可用的?​​高性能基于内存的存储Redis是基于内存的存储系统,所有数据都保存在内存中,这使得Redis可以快速读取和写入数据。与传统的基于磁盘存储的系统相比,Redis的读写性能更高。单线程的设计是单线程的设计,所有的读写请求都由同一个线程处理,避免了多线......
  • Chrome扩展开发实战:快速填充表单
    大家好,我是dom哥。我正在写关于Chrome扩展开发的系列文章,感兴趣的可以点个小星星。填表单是打工人经常面对的场景,作为一个前端,我经常开发一些PC端的页面,它们主要由表单和表格构成,而输入框又是表单里最常见的表单项。接下来就试着做一个简单的小扩展,用于快速给表单里的输入......
  • 创建一个Redis集群的启动命令并启动
    第一步:进入到存放集群的目录里cd/opt/cluster如下图[红线圈中的目录]:第二步:在此目录创建sh文件[示例为start.sh],并打开编辑vimstart.sh第三步:在文件中,写入要执行的所有Redis端口命令`redis-server/opt/cluster/6001/redis.confredis-server/opt/cluster/6002/redis.c......
  • RedisTemplate 使用 increasement() 和 get() 时报 SerializationException
    https://cloud.tencent.com/developer/article/1706934 org.springframework.data.redis.serializer.SerializationException:Cannotdeserialize;nestedexceptionisorg.springframework.core.serializer.support.SerializationFailedException:Failedtodeseriali......
  • quickjs C功能扩展的四种写法
    一、前言 茴香豆的“茴”字有多少种写法?这篇博客不是为了炫技,是JS就是这么多种情况。比如C语言,就只能通过函数调用,没有类的概念。比如Java,就只能通过类、对象的方式。不能单独创建函数。哪怕main函数也要包装成一个class。而JS,即可以提供函数,也可以提供类。在ES5之前,JS......