C# 基于 CSRedis 实现安全分布式锁的 Lua 脚本原理与封装

今天早睡
今天早睡
发布时间:2026-10-16| 2人浏览过
原创

在分布式系统中,基于 Redis 实现分布式锁是常见的并发控制手段。本文深入解析 C# 环境下使用 CSRedis 库构建安全分布式锁的实现细节,重点阐述如何利用 Lua 脚本保证“获取-删除”操作的原子性,从而杜绝锁被意外释放的风险。文中提供了经过简化的封装类代码,支持自定义 Token 管理及多实例连接。

分布式锁的基础原理

实现一个基础的分布式锁主要依赖 Redis 的原子命令。核心流程如下:

  • 加锁:使用 SET key token NX EX seconds 或 SETNX 命令。只有当 Key 不存在时才写入,同时设置过期时间以防止死锁。
  • 判断锁:通过 GET key 获取当前锁的值(Token)。
  • 解锁:使用 DEL key 删除锁。

虽然简单的命令组合看似可行,但在实际高并发场景中,直接执行 DEL 存在严重的隐患。如果锁设置了自动过期时间,当锁因超时自动释放后,另一个线程 A 成功获取了该锁。此时,第一个线程 B 由于网络延迟或处理缓慢,其之前发送的 DEL 命令才到达 Redis。这将导致线程 B 错误地释放了线程 A 持有的锁,造成并发冲突。

Lua 脚本确保原子性

为解决上述误删问题,必须保证“检查 Token”和“删除 Key”两个操作具有原子性。Redis 提供 EVAL 命令执行 Lua 脚本,脚本在 Redis 服务端串行执行,中间不会被其他命令插入。

标准的解锁 Lua 脚本逻辑如下:

if redis.call("get",KEYS[1]) == ARGV[1]
then
    return redis.call("del",KEYS[1])
else
    return 0
end

该脚本首先获取 Key 对应的值,并与传入的 Token(ARGV[1])进行比对。仅当两者完全一致时,才执行删除操作并返回 1;否则返回 0,表示无法释放非本机持有的锁。这种方式允许开发者在任何地方以观察者身份,只要知道正确的 Token,即可安全判断锁的状态甚至辅助清理(需严格授权)。

C# 封装实现

以下代码展示了如何基于 CSRedis 库封装一个简易的分布式锁管理器。相比官方库,此实现简化了续租功能,并将 Token 的控制权交给调用者,同时保持 Key 的原生结构不加前缀,便于调试和监控。

第1步:定义管理器和基础工具方法

创建一个 CsRedisManager 类,使用 ConcurrentDictionary 管理多个 Redis 客户端实例,并提供基础的读写、过期及脚本执行方法。

using CSRedis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

namespace CsRedis.Helper
{
    public class CsRedisManager
    {
        private ConcurrentDictionary<string, CSRedisClient> _serviceNameWithClient;

        public void Init()
        {
            _serviceNameWithClient = new ConcurrentDictionary<string, CSRedisClient>();
        }

        public CSRedisClient GetRedisClient(string serviceName)
        {
            CSRedisClient result = null;
            _serviceNameWithClient.TryGetValue(serviceName, out result);
            return result;
        }

        public bool AddRedisClient(string serviceName, string connectStr)
        {
            CSRedisClient cSRedisClient = new CSRedisClient(connectStr);
            return _serviceNameWithClient.TryAdd(serviceName, cSRedisClient);
        }

        // ... 省略 Set, Get, SetNx, Expire, Del 等基础包装方法 ... 
        // 这些方法内部均包含对 client 为空的校验及异常抛出

        /// <summary>
        /// 执行 Lua 脚本
        /// </summary>
        public object Eval(string serviceName, string script, string key, params object[] args)
        {
            var res = GetRedisClient(serviceName).Eval(script, key, args);
            return res;
        }
    }
}

第2步:实现加锁与解锁核心逻辑

加锁直接使用 SetNx(带过期时间的 SET NX)。解锁则调用预先定义的 Lua 脚本。

    public class CsRedisManager
    {
        // ... 前述字段和方法 ...

        /// <summary>
        /// 添加共享锁
        /// </summary>
        /// <param name="serviceName">Redis服务名称锁的Key唯一标识符(如GUID)毫秒数有效期

第3步:测试验证

在实际使用中,初始化管理器,添加 Redis 连接配置,然后模拟加锁和释放锁的过程。注意连接字符串中的密码和其他参数需根据实际环境调整。

using CsRedis.Helper;
using NUnit.Framework;

namespace TestProject
{
    public class Tests
    {
        [Test]
        public void TestLockUnlock()
        {
            var csRedisManager = new CsRedisManager();
            csRedisManager.Init();
            
            // 添加 Redis 客户端,请替换实际连接串
            csRedisManager.AddRedisClient("TEST", "127.0.0.1:6379,password=YourPassword,
connectTimeout=1000,syncTimeout=10000,defaultDatabase=0");

            var token = Guid.NewGuid().ToString();
            var lockKey = "LOCKKEY1";
            
            // 加锁,有效期20秒(传入毫秒数)
            var isLocked = csRedisManager.AddLock("TEST", lockKey, token, 20 * 1000);
            Assert.IsTrue(isLocked);

            // 释放锁
            var isReleased = csRedisManager.ReleaseLock("TEST", lockKey, token);
            Assert.IsTrue(isReleased);
        }
    }
}

总结

通过在 C# 中结合 CSRedis 库与 Lua 脚本,可以有效构建具备高可靠性的分布式锁。关键在于利用 Token 机制区分不同线程/客户端持有的锁,并利用 Lua 脚本保证释放锁时的条件检查与执行原子性,从而避免由网络延迟导致的锁误删问题。以上就是基于 CSRedis 实现分布式锁的详细内容,更多关于 C# Redis 高级应用的技术资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。