zoukankan      html  css  js  c++  java
  • redis分布式锁秒杀

    1.采用redis分布式锁

    using RedLockNet.SERedis;
    using ServiceStack.Redis;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace DotnetDocker.Models
    {
        public class RedisUtitily
        {
            public static string RedisServerIp = "192.168.0.107";
            public static int RedisServerPort = 6379;
    
            public static object LockObject = new object();
            public static string keylock = "redislock";
    
            public static RedLockFactory redLockFactory = RedLockUtitily.GetRedlockFactory();
    
    
            public static RedisClient GetClient()
            {
                return new RedisClient(RedisServerIp, RedisServerPort);
            }
            public static void Test()
            {
                var lockValue = Guid.NewGuid().ToString() + Thread.CurrentThread.ManagedThreadId;
                //var rLock = redLockFactory.CreateLock(keylock, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(20));
                try
                {
                    using (RedisClient client = GetClient())
                    {
                        var flag = client.SetValueIfNotExists(keylock, lockValue, TimeSpan.FromSeconds(60));
                        if (flag)
                        {
                            //var a = redisClient.Get("test123");
                            var count = client.Get<int>("good:001");
                            if (count <= 0)
                            {
                                Console.WriteLine("good:001商品已经卖光");
                            }
                            else
                            {
                                client.Decr("good:001");
                                Console.WriteLine($"第{count}件商品被购买");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine($"Error:{ex.Message}");
                }
                finally
                {
                    using (RedisClient client = GetClient())
                    {
                        try
                        {
                            var lua = $"if redis.call("get", KEYS[1]) == ARGV[1] then" +
                                    "  return redis.call("del", KEYS[1])" +
                                  "  else" +
                                    "  return 0" +
                                   "  end";
    
                            int res = (int)client.ExecLuaAsInt(lua, keys: new string[] { keylock }, args: new string[] { lockValue });
                            if (res == 1)
                            {
                                Console.WriteLine($"删除key成功{lockValue}");
                            }
                            else
                            {
                                Console.WriteLine($"删除key失败{lockValue}");
                            }
                        }
                        catch (Exception ex) {
                            Console.WriteLine($"error:{ex.Message}");
                        }
                    }
                    //rLock.Dispose();
                    //redLockFactory.Dispose();
    
                }
    
            }
    
            public static void TestRedLock()
            {
                var lockValue = Guid.NewGuid().ToString() + Thread.CurrentThread.ManagedThreadId;
            //expire 锁过期时间
            //wait 线程等待时间,如果更呆了wait时间还没有获得锁,放弃
            //retry //每隔多长时间试着获取锁
    var rLock = redLockFactory.CreateLock(keylock, TimeSpan.FromSeconds(10), TimeSpan.FromSeconds(5), TimeSpan.FromMilliseconds(20)); try { using (RedisClient client = GetClient()) { if (rLock.IsAcquired) { //var a = redisClient.Get("test123"); var count = client.Get<int>("good:001"); if (count <= 0) { Console.WriteLine("good:001商品已经卖光"); } else { client.Decr("good:001"); Console.WriteLine($"第{count}件商品被购买"); } } } } catch (Exception ex) { Console.WriteLine($"Error:{ex.Message}"); } finally { rLock.Dispose(); Console.WriteLine($"finally {lockValue}"); } } } }

    采用redlock.net是,需要因拥抱并写一个创建锁的工厂类

    using RedLockNet.SERedis;
    using RedLockNet.SERedis.Configuration;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Threading.Tasks;
    
    namespace DotnetDocker.Models
    {
        public class RedLockUtitily
        {
            public static RedLockFactory GetRedlockFactory() {
                var endPoints = new List<RedLockEndPoint>();
                endPoints.Add(new DnsEndPoint("192.168.0.107",6379));
    
                return RedLockFactory.Create(endPoints);
            }
        }
    }
    

      当同时有100个线程时,要注意线程变量。线程变量作用域只在本线程,线程间不可共享

    所以,下面的keyLock值不同线程是不同的。

    秒杀可以用下面这种lua脚本,不过多线程会出现超卖

           public static void SecKill(int  j) {
                for (int i = 0; i < 10; i++) {
                    using (RedisClient client = new RedisClient("192.168.145.128", 6379))
                    {
                        //var num = client.Decr("number");
                        var num = client.Get<int>("number");
                        if (num > 0)
                        {
                            var lua = @"local count = redis.call('get',KEYS[1]) 
                                        if(tonumber(count) > 0)
                                        then
                                            redis.call('INCR',ARGV[1])
                                            return redis.call('DECR',KEYS[1])
                                        else
                                            return -1
                                        end
                            ";
                            var result = client.ExecLuaAsInt(lua, keys: new string[] { "number"}, args: new string[] { "sellnumber" });
                            var leftnum = client.Get<int>("number");
                            if (result == -1) {
                                Console.WriteLine($"{j}抢购失败,10个买完了-{result}");
                            }
                            else { 
                                Console.WriteLine($"{j}抢购成功,TaskId:{Task.CurrentId},ThreadId: {Thread.CurrentThread.ManagedThreadId}-{result}");
                            }
                            //client.Set<int>("number", --num);
                        }
                        else
                        {
                            Console.WriteLine($"{j}抢购失败");
                        }
                    };
                }
            }
  • 相关阅读:
    log4net 简单使用教程(配置)
    C#WinForm 国际化的简单实现,多语言实现
    EF Power Tool 参数错误 HRESULT:0x80070057 (E_INVALIDARG)) 解决办法
    如何用委托与事件实现winfrom窗体之间值传递
    VS2010自带的Dotfuscator 5注册
    WinForm 实现主程序(exe)与其关联类库(*.dll)分开存放
    POJ_3211 Washing Clothes (01背包)
    POJ_3624 Charm Bracelet ( 01背包 )
    集训队内部测试赛(2012.01.02)
    HDU_1011 Starship Troopers && HDU_1561 The more, The Better (树型dp)
  • 原文地址:https://www.cnblogs.com/kingsmart/p/15552718.html
Copyright © 2011-2022 走看看