分布式锁不适用于 RedLock.net

问题描述 投票:0回答:2

我想用Redis做分布式锁。我为此使用 RedLock.net nuget 包。 但是线程能够获取锁,即使另一个线程已经获取了锁。

这是示例代码:

public void Demo(RedLockFactory redLockFactory)
        {
            Parallel.For(0, 5, x =>
            {
                TimeSpan expiry = TimeSpan.FromSeconds(30);
                var wait = TimeSpan.FromSeconds(10);
                var retry = TimeSpan.FromSeconds(1);

                string user = $"User:{x}";
                using (var redLock = redLockFactory.CreateLock(resource, expiry, wait, retry))
                {

                    // make sure we got the lock
                    if (redLock.IsAcquired)
                    {
                        Console.WriteLine($"{user} acquired lock at {DateTimeOffset.Now.ToString("dd-MM-yyyy HH:mm:ss")}.");
                    }
                    else
                    {
                        Console.WriteLine($"{user} didn't get the lock.");
                    }
                }
            });
        }

这是我的演示的输出

User:4 acquired lock at 06-10-2020 09:24:34.
User:2 acquired lock at 06-10-2020 09:24:34.
User:1 acquired lock at 06-10-2020 09:24:34.
User:0 acquired lock at 06-10-2020 09:24:35.
User:3 acquired lock at 06-10-2020 09:24:35.

如您所见,每个线程都能够获取锁,这是不应该发生的。

一旦获取锁,其他线程就不能获取锁。

c# asp.net-core redis stackexchange.redis redlock.net
2个回答
4
投票

Per RedLock.net/README.md,“锁在 using 块结束时自动释放”。

所以我认为您的演示输出中发生的情况是:

  1. 五个线程并行启动,每个线程都尝试锁定同一资源。
  2. 线程 4 获胜(成功获取其锁)并执行以下操作;与此同时,其他线程等待(最多 10 秒):
    • 将“获取的锁”写入控制台
    • 传出
      using
      块,释放其锁(现在另一个线程可以获胜)
  3. 线程 2 获胜并在其余线程等待时执行相同的操作。
  4. 线程 1、0 和 3 也是如此。
  5. 每个线程都快速完成工作,因此没有线程在 10 秒内无法获取锁。

如果您想看到锁获取失败,请在退出

using
块之前执行非常慢的操作(>10 秒)。出于演示目的,您可以在写完“acquired”行后
Thread.Sleep(15000)


0
投票

这里是 RedLock.Net 的一个更好的示例测试。 使用的时间跨度适用于我的应用程序。 每个线程最终都应该获得锁,但是您可以看到每个线程获取锁之间的等待时间。

public static void Main() {
    List<RedLockEndPoint> endPoints = [
        new DnsEndPoint("localhost", 6379)
    ];

    RedLockFactory redLockFactory = RedLockFactory.Create(endPoints);

    Parallel.For(0, 10, x => {
        TimeSpan expiry = TimeSpan.FromSeconds(120);

        TimeSpan wait  = TimeSpan.FromSeconds(60);
        TimeSpan retry = TimeSpan.FromSeconds(5);

        using IRedLock? redLock = redLockFactory.CreateLock("123456", expiry, wait, retry);

        if (redLock.IsAcquired) {
            Console.WriteLine($"User:{x} acquired lock at {DateTimeOffset.Now:dd-MM-yyyy HH:mm:ss}.");

            Task.Delay(500 * x).GetAwaiter().GetResult();
        }
        else {
            Console.WriteLine($"User:{x} didn't get the lock.");
        }
    });
}
© www.soinside.com 2019 - 2024. All rights reserved.