闸机控制系统从设计到实现全解析:第 4 篇:Redis 缓存与分布式锁实现

第 4 篇:Redis 缓存与分布式锁实现

一、Redis 在系统中的核心作用
  1. 票证信息缓存:将高频访问的票证数据(如状态、有效期)缓存至 Redis,减少数据库查询,提升验证响应速度。

  2. 分布式锁:在高并发场景下,防止同一张票被同时验证,确保 "一票一次" 机制的可靠性。

  3. 闸机状态缓存:实时存储闸机开关状态,便于前端监控与管理。

二、Redis 集成步骤
  1. 安装 StackExchange.Redis
bash 复制代码
dotnet add package StackExchange.Redis
  1. 注册 Redis 服务:在 Program.cs 中配置连接:
csharp 复制代码
builder.Services.AddSingleton\<IConnectionMultiplexer>(

   ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis")));
  1. 封装 Redis 操作工具类
csharp 复制代码
public class RedisHelper

{

   private readonly IDatabase _db;

  

   public RedisHelper(IConnectionMultiplexer redis)

   {

       _db = redis.GetDatabase();

   }

  

   // 设置缓存(带过期时间)

   public async Task SetAsync(string key, string value, TimeSpan? expiry = null)

   {

       await _db.StringSetAsync(key, value, expiry);

   }

  

   // 获取缓存

   public async Task<string> GetAsync(string key)

   {

       return await _db.StringGetAsync(key);

   }

}
三、分布式锁实现

分布式锁核心特性

  • 互斥性:同一时间只有一个节点能获取锁。
  • 安全性:避免死锁(锁必须有过期时间),不能误删他人的锁。
  • 可用性:Redis 故障时仍能基本可用(如主从切换)。
  • 重入性:同一线程可重复获取锁(可选,视场景而定)。
csharp 复制代码
public class RedisDistributedLock

{

   private readonly IDatabase _db;

   private readonly string _lockPrefix = "lock:";

  

   public RedisDistributedLock(IConnectionMultiplexer redis)

   {

       _db = redis.GetDatabase();

   }

  

   // 获取锁(返回锁标识,用于释放)

   public async Task<string> AcquireLockAsync(string resource, TimeSpan expiry)

   {

       var lockKey = _lockPrefix + resource;

       var lockValue = Guid.NewGuid().ToString(); // 唯一标识,防止误释放

      

       // SET NX(不存在则设置)+ PX(过期时间)

       var acquired = await _db.StringSetAsync(

           lockKey, lockValue, expiry, When.NotExists);

          

       return acquired ? lockValue : null;

   }

  

   // 释放锁(Lua脚本保证原子性)

   public async Task ReleaseLockAsync(string resource, string lockValue)

   {

       var lockKey = _lockPrefix + resource;

       var script = @"

           if redis.call('get', KEYS\[1]) == ARGV\[1] then

               return redis.call('del', KEYS\[1])

           else

               return 0

           end";

      

       await _db.ScriptEvaluateAsync(script, new RedisKey\[] { lockKey },

           new RedisValue[] { lockValue });

   }

}

c

  • 缓存更新:票证状态变更(如使用后)时,同步更新 Redis 缓存。

  • 过期时间:票证缓存设置与票证有效期关联,避免缓存冗余。

  • 缓存穿透防护:对不存在的票证,缓存空值(短期过期),减少无效数据库查询。

五、缓存常见问题
问题 描述 解决方案
缓存穿透 查询不存在的数据,穿透到DB 1. 缓存空值(短期过期);2. 布隆过滤器预过滤不存在的key
缓存击穿 热点key过期瞬间大量请求DB 1. 互斥锁(查询时加锁,只让一个线程更新缓存);2. 热点key永不过期
缓存雪崩 大量key同时过期,请求压垮DB 1. 过期时间加随机值(分散过期);2. 服务熔断/降级;3. 缓存集群高可用

六、注意事项

  1. Redis 部署方式

    • 单机部署:锁性能高,但存在单点故障风险。
    • 主从+哨兵:提高可用性,但主从切换时可能出现"锁丢失"(可通过 Redisson 的 RedLock 算法缓解,但性能有损耗)。
  2. 锁超时处理

    • 锁过期时间需大于业务执行时间,避免业务未完成锁已释放。
    • 可使用"锁续期"机制(如 Redisson 的 Watch Dog),自动延长锁有效期。
  3. 缓存与锁的结合

    • 缓存更新时需加锁避免并发问题(如缓存击穿场景)。
    • 分布式锁的粒度应尽量小,避免影响性能。
总结
  • Redis 缓存:通过合理的缓存策略(如 Cache-Aside)和问题解决方案,可显著提升系统性能。
  • 分布式锁 :基于 Redis 的 SET NX PX 命令可实现基础锁,生产环境推荐使用 Redisson 简化开发并避免潜在问题。

两者结合可有效解决分布式系统中的性能与并发安全问题。

相关推荐
刃神太酷啦2 小时前
Redis 核心进阶:哨兵、集群、缓存问题与分布式锁详解----《Hello Redis!》(6)
linux·c语言·数据库·c++·redis·分布式·缓存
名字还没想好☜3 小时前
Python 的 __call__ 实战:让实例像函数一样被调用,做带状态计数器、缓存器与可配置策略
开发语言·后端·python·缓存·编程语言
suweijie7683 小时前
Redis 7.0.2 Docker Compose 部署
redis·docker
爱和冰阔落4 小时前
【Linux】手写日志与固定线程池:任务队列、工作线程和安全退出
linux·运维·c++·redis·安卓
海宇大数据4 小时前
分布式网关架构实战:基于海宇数据公安二要素认证即时版构建自动化司机准入网关
人工智能·分布式·架构·自动化
像风一样自由20205 小时前
29.Redis在大模型应用中有哪些用途缓存会话与限流
数据库·人工智能·redis·缓存·大模型·milvus·智能体
weixin_460443569 小时前
考试监控大屏为什么不能直接查数据库?WebSocket、Redis与实时数据聚合架构设计
数据库·redis·在线考试系统·培训考试系统·煤矿培训考试系统·煤矿在线考试系统·宏远培训考试系统
九皇叔叔13 小时前
【第二章】Redis基础入门:Redis是什么、为什么快以及核心特性详解
数据库·redis·缓存
木圭的AI时代指南16 小时前
Spark-X2.5 长输入 Agent 实测:全量读取陷阱与解释器寻找死循环复盘,附可复现任务
大数据·分布式·spark
敲代码的嘎仔1 天前
用 Redis 合并写 + DelayQueue 延迟检测,把视频播放进度写库频率降到 1/60
java·开发语言·数据库·redis·缓存·音视频·高并发