网站首页 > 技术文章 正文
在分布式系统中,多个服务实例可能同时访问共享资源,为避免并发问题,需要引入一种可靠的分布式锁机制。
本文介绍如何在 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. 启动 Redis 实例:确保 Redis 正在运行(推荐使用多实例)。
- 2. 注册服务:在 Startup.cs 中注册 DistributedLockService。
- 3. 调用接口:通过 HTTP 请求触发受锁保护的操作。
- 4. 异常处理:未获取到锁时返回 429 Too Many Requests。
欢迎关注我的公众号“Net分享”,技术文章第一时间推送,随缘更新 , 分享一些你可能注意不到的细节
猜你喜欢
- 2025-07-03 探索 Swift 中的 MVC-N 模式(mvc模式是什么)
- 2025-07-03 彻底搞懂Spring依赖注入(一)Bean实例创建过程
- 2025-07-03 Spring IoC Container 原理解析(spring中ioc的作用与原理)
- 2025-07-03 Spirng 循环依赖报错:Is there an unresolvable circular reference?
- 2024-08-03 详解模板注入漏洞(下)(模版注入)
- 2024-08-03 基于 Mixerless Telemetry 实现渐进式灰度发布系列 3 渐进式灰度发布
- 2024-08-03 OOP 思想在 TCC/APIX/GORM 源码中的应用
- 2024-08-03 如何通过 Istio 实现微服务特性(activiti微服务)
- 2024-08-03 001 | 搭上SpringBoot自动注入源码分析专车
- 2024-08-03 Spring IoC:@Autowire 详解(springioc di)
- 最近发表
-
- count(*)、count1(1)、count(主键)、count(字段) 哪个更快?
- 深入探索 Spring Boot3 中 MyBatis 的 association 标签用法
- js异步操作 Promise fetch API 带来的网络请求变革—仙盟创梦IDE
- HTTP状态码超详细说明_http 状态码有哪些
- 聊聊跨域的原理与解决方法_跨域解决方案及原理
- 告别懵圈!产品新人的接口文档轻松入门指南
- 在Javaweb中实现发送简单邮件_java web发布
- 优化必备基础:Oracle中常见的三种表连接方式
- Oracle常用工具使用 - AWR_oracle工具有哪些
- 搭载USB 3.1接口:msi 微星 发布 990FXA Gaming 游戏主板
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- js判断是否是json字符串 (75)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)