redis分布式锁秒杀

2021/11/15 2:14:37

本文主要是介绍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}抢购失败");
                    }
                };
            }
        }

 



这篇关于redis分布式锁秒杀的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程