优秀的编程知识分享平台

网站首页 > 技术文章 正文

在 ASP.NET Core 中基于 RedLock.net 实现高可用分布式锁方案

nanyue 2025-07-03 18:31:29 技术文章 3 ℃

在分布式系统中,多个服务实例可能同时访问共享资源,为避免并发问题,需要引入一种可靠的分布式锁机制。

本文介绍如何在 ASP.NET Core 应用中使用 RedLock.net 实现基于 Redis 的分布式锁,并结合依赖注入进行封装,以便在业务逻辑中安全地使用。


RedLock 算法概述

RedLock 是由 Redis 作者提出的一种用于构建高可用分布式锁的算法。其核心思想是:

向多个独立的 Redis 节点申请锁,只有超过半数节点成功获取锁时,才认为锁获取成功。

该算法旨在解决单点故障和网络分区带来的不可靠性问题。

关键参数

  • o expiry:锁的最大存活时间(防止死锁)
  • o wait:等待获取锁的最大时间
  • o retry:重试间隔时间

项目依赖与安装

所需 NuGet 包

dotnet add package RedLock.net --version 2.3.2
dotnet add package StackExchange.Redis

核心组件设计

DistributedLockService

这是对 RedLock 功能的封装类,负责创建并管理锁的生命周期。

using Microsoft.Extensions.Configuration;
using RedLockNet.SERedis;
using RedLockNet.SERedis.Configuration;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace DistributedLockSample.Services
{
    public class DistributedLockService : IDisposable
    {
        private readonly RedLockFactory _redLockFactory;
        private readonly IConnectionMultiplexer _redisConnection;

        public DistributedLockService(IConfiguration configuration)
        {
            var redisConnectionString = configuration.GetConnectionString("Redis");
            _redisConnection = ConnectionMultiplexer.Connect(redisConnectionString);

            var redisMultiplexers = new List<RedLockMultiplexer>
            {
                new RedLockMultiplexer(_redisConnection)
            };
            _redLockFactory = RedLockFactory.Create(redisMultiplexers);
        }

        public async Task<bool> ExecuteWithLockAsync(string resource, Func<Task> action)
        {
            var expiry = TimeSpan.FromSeconds(30); 
            var wait = TimeSpan.FromSeconds(10);  
            var retry = TimeSpan.FromSeconds(1);  

            await using var redLock = await _redLockFactory.CreateLockAsync(resource, expiry, wait, retry);

            if (redLock.IsAcquired)
            {
                try
                {
                    await action();
                    return true;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(#34;Error executing action: {ex.Message}");
                    return false;
                }
            }

            Console.WriteLine(#34;Failed to acquire lock for resource: {resource}");
            return false;
        }

        public void Dispose()
        {
            _redLockFactory?.Dispose();
            _redisConnection?.Dispose();
        }
    }
}

说明:

  • o RedLockMultiplexer 是对 IConnectionMultiplexer 的封装。
  • o 推荐使用至少 3 个独立 Redis 实例 来保证 RedLock 的可靠性。

Startup 配置

DistributedLockService 注册为单例服务:

using Microsoft.Extensions.DependencyInjection;
using DistributedLockSample.Services;

services.AddSingleton<DistributedLockService>();
services.AddControllers();

控制器调用

定义一个 API 接口,在执行敏感操作前获取锁:

using Microsoft.AspNetCore.Mvc;
using DistributedLockSample.Services;
using System.Threading.Tasks;

namespace DistributedLockSample.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ExampleController : ControllerBase
    {
        private readonly DistributedLockService _lockService;

        public ExampleController(DistributedLockService lockService)
        {
            _lockService = lockService;
        }

        [HttpPost("process/{resourceId}")]
        public async Task<IActionResult> ProcessResource(string resourceId)
        {
            var result = await _lockService.ExecuteWithLockAsync(
                resource: #34;resource:{resourceId}",
                action: async () =>
                {
                    await Task.Delay(1000); // 模拟业务处理
                    Console.WriteLine(#34;Processing resource {resourceId} at {DateTime.Now}");
                });

            if (result)
            {
                return Ok(#34;Successfully processed resource {resourceId}");
            }

            return StatusCode(429, #34;Failed to acquire lock for resource {resourceId}");
        }
    }
}

配置文件说明

appsettings.json 中添加 Redis 连接字符串:

{
  "ConnectionStrings": {
    "Redis": "localhost:6379"
  }
}

使用说明

  1. 1. 启动 Redis 实例:确保 Redis 正在运行(推荐使用多实例)。
  2. 2. 注册服务:在 Startup.cs 中注册 DistributedLockService
  3. 3. 调用接口:通过 HTTP 请求触发受锁保护的操作。
  4. 4. 异常处理:未获取到锁时返回 429 Too Many Requests

欢迎关注我的公众号“Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节

最近发表
标签列表