C#与Redis实战:基于StackExchange.Redis的数据操作全解析

C#与Redis实战:基于StackExchange.Redis的数据操作全解析 1. 环境准备与基础配置第一次接触Redis时我被它惊人的读写性能震撼到了。作为C#开发者选择StackExchange.Redis这个开源客户端绝对是明智之举。记得当时为了测试性能我用本地Docker快速搭建了一个Redis实例整个过程不到5分钟。如果你还没安装Redis推荐直接通过Docker运行docker run --name myredis -p 6379:6379 -d redis在Visual Studio中新建控制台项目后通过NuGet添加StackExchange.Redis只需两步右键项目选择管理NuGet程序包搜索并安装StackExchange.Redis当前稳定版是2.6.66连接字符串的配置有个小技巧我习惯用ConfigurationOptions对象而不是纯字符串因为可以更灵活地设置重试策略、超时等参数。这是我常用的初始化代码var config new ConfigurationOptions { EndPoints { localhost:6379 }, ConnectTimeout 5000, // 5秒连接超时 SyncTimeout 10000, // 10秒操作超时 AbortOnConnectFail false // 自动重连 }; ConnectionMultiplexer redis ConnectionMultiplexer.Connect(config);2. 字符串操作实战字符串是Redis最基础的数据类型但千万别小看它。去年我们项目就用字符串缓存实现了电商秒杀系统QPS轻松突破10万。来看几个实用场景场景1带过期时间的缓存IDatabase db redis.GetDatabase(); // 缓存用户会话30分钟自动过期 db.StringSet(user:1001:session, session_token, TimeSpan.FromMinutes(30)); // 原子性计数器 db.StringIncrement(product:2002:views); // 阅读量1场景2对象序列化存储配合Json.NET可以优雅地存储复杂对象var user new { Id 1001, Name 张三, LastLogin DateTime.Now }; db.StringSet(user:1001, JsonConvert.SerializeObject(user)); // 反序列化读取 var userData JsonConvert.DeserializeObject(db.StringGet(user:1001));踩坑提醒StringSet默认是覆盖写入如果需要不存在时才设置的原子操作要加上条件db.StringSet(lock:order, locked, when: When.NotExists);3. 哈希表高级用法哈希特别适合存储对象属性我们用户系统的个人资料就全用Hash存储。对比字符串存储整个对象Hash可以精准修改单个字段// 存储用户属性 db.HashSet(user:1001, new HashEntry[] { new HashEntry(name, 李四), new HashEntry(age, 28), new HashEntry(vip, true) }); // 只获取部分字段 var userName db.HashGet(user:1001, name); // 原子性字段自增 db.HashIncrement(user:1001, login_count);有个性能优化技巧批量操作时使用HashGetAll比多次HashGet更高效。我们做过测试获取10个字段时批量操作能快3-5倍。4. 列表与集合实战列表实现消息队列我们日志系统就用Redis列表做缓冲队列// 生产者 db.ListRightPush(log:queue, error: connection timeout); // 消费者 while(true) { var log db.ListLeftPop(log:queue); if (!log.IsNull) ProcessLog(log); else Thread.Sleep(100); }集合去重应用处理用户标签时集合自动去重的特性太有用了// 添加用户标签 db.SetAdd(user:1001:tags, 电子产品); db.SetAdd(user:1001:tags, 数码爱好者); // 获取共同兴趣 db.SetIntersect(user:1001:tags, user:1002:tags);5. 有序集合深度应用有序集合在我们排行榜功能中表现惊艳。比如实现直播打赏榜// 更新主播热度值 db.SortedSetIncrement(live:ranking, 主播A, 500); // 获取TOP10 var top10 db.SortedSetRangeByRank(live:ranking, 0, 9, Order.Descending); // 带分数返回 var topWithScores db.SortedSetRangeByRankWithScores(live:ranking, 0, 4, Order.Descending);有个实用技巧使用SortedSetCombine可以合并多个榜单我们用它实现了跨服游戏排行榜。6. 键管理与生产实践键命名规范经过多个项目总结推荐这样的命名规则业务:子业务:ID[:属性] 例如 order:20230815:10086:status user:1001:profile批量操作优化使用管道(Pipeline)能大幅提升批量操作性能var batch db.CreateBatch(); batch.StringSetAsync(key1, value1); batch.StringSetAsync(key2, value2); batch.Execute();连接复用技巧千万别每次操作都创建新连接最佳实践是全局维护一个ConnectionMultiplexer实例。我们在ASP.NET Core中通常这样注册services.AddSingletonIConnectionMultiplexer( ConnectionMultiplexer.Connect(configuration));7. 性能调优经验在日均亿级请求的系统中我们总结出这些黄金法则合理设置过期时间即使是持久化数据也建议设置TTL防止冷数据堆积控制Value大小单个Value不要超过10KB大Value考虑分片存储慎用KEYS命令生产环境绝对禁用KEYS *用SCAN替代监控慢查询定期检查slowlog发现性能瓶颈// 获取慢查询日志 var slowLog redis.GetServer(localhost, 6379).SlowlogGet();8. 异常处理与调试Redis操作必须做好错误处理特别是网络波动时的重试机制。这是我们封装的安全操作模板try { var tran db.CreateTransaction(); tran.AddCondition(Condition.StringEqual(lock:order, true)); tran.StringSetAsync(order:1001, paid); bool committed tran.Execute(); } catch(RedisConnectionException ex) { // 处理网络异常 logger.Error(Redis连接失败, ex); } catch(RedisTimeoutException ex) { // 处理超时 logger.Warn(操作超时, ex); }调试时推荐使用RedisInsight工具它能直观展示数据结构比命令行友好多了。