跳到主要内容
版本:3.0.0

Redis

这页对应 3.x 里的 Redis 使用方式,核心组件是 Redis 缓存(Aegis.Caching.Redis)。其他和 Redis 相关的能力,如 Redis 会话、Redis ID 容器、Redis 事件总线,都是建立在这层基础能力之上的。

先记住 Redis 的边界

当前 Redis 体系主要分成两层:

  • Aegis.Caching.Redis 负责 Redis 数据源、脚本管理和基础访问
  • 其他扩展组件在这层之上实现认证会话、ID 容器或事件容器

所以 Redis 接入的第一步通常不是改 Component.deps.json,而是:

  1. 准备 Redis 配置
  2. 定义 RedisSource
  3. 在服务注册阶段执行 AddRedisSource<T>()

最小接入方式

1. 准备 Redis 配置

{
"Redis": {
"RedisMode": "Standalone",
"ConnectionString": "127.0.0.1:6379,defaultDatabase=2",
"SentinelString": "",
"IsRWSplitting": true,
"ScriptPath": ""
}
}

2. 定义自己的 RedisSource

public class AegisRedisSource : RedisSourceBase
{
public AegisRedisSource(RedisOptions redisOptions) : base(redisOptions)
{
}
}

3. 在服务注册阶段注入

services.AddRedisSource<AegisRedisSource>(
ConfigManager.Get<RedisOptions>("Redis"));

4. 在业务类中直接注入

public class UserService : IUserContract
{
private readonly AegisRedisSource _redis;

public UserService(AegisRedisSource redis)
{
_redis = redis;
}
}

四种最常见的模式怎么配

单实例

{
"Redis": {
"RedisMode": "Standalone",
"ConnectionString": "127.0.0.1:6379,defaultDatabase=2",
"SentinelString": "",
"IsRWSplitting": false,
"ScriptPath": ""
}
}

主从

{
"Redis": {
"RedisMode": "MasterSlave",
"ConnectionString": "10.0.0.11:6379;10.0.0.12:6379,defaultDatabase=2",
"SentinelString": "",
"IsRWSplitting": true,
"ScriptPath": ""
}
}

哨兵

{
"Redis": {
"RedisMode": "Sentinel",
"ConnectionString": "10.0.0.11:26379;10.0.0.12:26379;10.0.0.13:26379",
"SentinelString": "mymaster,defaultDatabase=2",
"IsRWSplitting": true,
"ScriptPath": "{CurrentDirectory}/Scripts/"
}
}

集群

{
"Redis": {
"RedisMode": "Cluster",
"ConnectionString": "10.0.0.21:6379;10.0.0.22:6379;10.0.0.23:6379",
"SentinelString": "",
"IsRWSplitting": false,
"ScriptPath": ""
}
}

常见配置项怎么理解

配置项作用
RedisMode指定 Redis 拓扑模式
ConnectionString主连接串,单节点或多节点地址写在这里
SentinelString哨兵模式下的补充参数
IsRWSplitting是否读写分离
ScriptPath启动时统一加载脚本的目录

如果你们后面还要做多级缓存或降级保护,还会继续用到:

配置项作用
Resilience.Score降级前分值上限
Resilience.RecoverScore恢复所需分值
Resilience.HeartBeatInterval心跳间隔
Resilience.FallbackPolicy出故障时是降级还是直接抛错
L1Cache.Enabled是否开启本地一级缓存

RedisSource 最常见的几类操作

读写普通对象

await _redis.SetAsync("user:1001", user, 300);

var user = await _redis.GetAsync<UserDto>("user:1001");

await _redis.DelAsync("user:1001");

操作集合

await _redis.SAddAsync("role:admin", "1001");
await _redis.SRemAsync("role:admin", "1001");

var diff = await _redis.SDiffAsync("role:admin", "role:guest");

操作哈希字段

await _redis.HSetAsync("doctor:1001", "name", "张三");

var doctorName = await _redis.HGetAsync<string>("doctor:1001", "name");

var hasName = await _redis.HExistsAsync("doctor:1001", "name");

脚本管理怎么接

如果项目里有 Lua 脚本,最省心的做法是统一放到一个目录,让 RedisSource 启动时自动加载。

配置脚本目录

{
"Redis": {
"ScriptPath": "{CurrentDirectory}/Scripts/"
}
}

手动追加脚本

_redis.Scripts.AddScript("GetBiLocker", luaContent);

追加脚本文件

_redis.Scripts.AddScriptByPath("C:\\Scripts\\GetBiLocker.lua");

执行脚本

var result = _redis.Scripts.ExecuteScript(
"GetBiLocker",
"lock:key",
new object[] { "inputKey", 30 });

BiLocker 怎么用

Redis 里当前还提供了一组双边锁能力,常见用途是把一对互斥关系写到同一个主键空间下,例如床位双向占用、左右映射关系、成对绑定关系等。

先准备脚本目录

BiLocker 依赖 Redis 脚本,所以要先保证脚本目录已经被 RedisSource 正常加载。

{
"Redis": {
"ScriptPath": "{CurrentDirectory}/Scripts/"
}
}

设置双边锁

var isLocked = await _redis.Scripts.SetBiLock(
"BedLock",
key1,
key2,
timeout: 30,
isForce: false,
side: BiLockSide.Left);

检查某一侧是否已经被锁定

var isLocked = await _redis.Scripts.CheckBiLock(
"BedLock",
key1,
BiLockSide.Left);

释放双边锁

var removed = await _redis.Scripts.RemoveBiLock(
"BedLock",
key1,
BiLockSide.Left);

刷新双边锁过期时间

var refreshed = await _redis.Scripts.RefreshBiLock(
"BedLock",
leftKey: "A",
rightKey: "B",
delaySeconds: 30);

BiLockSide 表示什么

枚举值说明
BiLockSide.Left以左侧身份参与当前锁关系
BiLockSide.Right以右侧身份参与当前锁关系

什么时候适合用 isForce

isForce = false 更适合正常业务锁定。
只有你已经确认需要强制覆盖旧锁关系时,再考虑设为 true

一个项目接多个 Redis 怎么办

不要在一个 RedisSource 里硬塞多个配置。
更稳的做法是给不同用途定义不同的 RedisSource

public class BizRedisSource : RedisSourceBase
{
public BizRedisSource(RedisOptions redisOptions) : base(redisOptions)
{
}
}

public class SessionRedisSource : RedisSourceBase
{
public SessionRedisSource(RedisOptions redisOptions) : base(redisOptions)
{
}
}

然后分别绑定:

services.AddRedisSource<BizRedisSource>(
ConfigManager.Get<RedisOptions>("BizRedis"));

services.AddRedisSource<SessionRedisSource>(
ConfigManager.Get<RedisOptions>("SessionRedis"));

什么时候要继续看其他 Redis 相关文档

要把登录态放到 Redis

Redis 用户会话(Aegis.Authorization.RedisUserManager)

要给 ID 生成器加 Redis 容器

ID生成器Aegis.IdGenerator.Provider.Redis

要给事件总线加 Redis 容器

Aegis.EventBus.Container.Redis

要给业务加多级缓存

多级缓存

常见问题

为什么配置写了,但容器里还是拿不到 RedisSource

因为 Redis 不是自动装配组件。
只写配置不够,还必须执行 AddRedisSource<T>()

为什么一启动就报脚本目录错误

如果 ScriptPath 有值,目录就必须真实存在。
当前项目没有脚本时,直接设为空字符串最稳。

为什么 Redis 底座接好了,但登录态还是没共享

因为 Redis 底座只负责连上 Redis。
登录态共享还要继续接 RedisUserManager

推荐阅读顺序

  1. Redis 缓存(Aegis.Caching.Redis)
  2. 配置
  3. Redis 用户会话(Aegis.Authorization.RedisUserManager)
  4. 多级缓存