![]() |
VOOZH | about |
dotnet add package Galosys.Foundation.StackExchange.Redis --version 26.5.20.1
NuGet\Install-Package Galosys.Foundation.StackExchange.Redis -Version 26.5.20.1
<PackageReference Include="Galosys.Foundation.StackExchange.Redis" Version="26.5.20.1" />
<PackageVersion Include="Galosys.Foundation.StackExchange.Redis" Version="26.5.20.1" />Directory.Packages.props
<PackageReference Include="Galosys.Foundation.StackExchange.Redis" />Project file
paket add Galosys.Foundation.StackExchange.Redis --version 26.5.20.1
#r "nuget: Galosys.Foundation.StackExchange.Redis, 26.5.20.1"
#:package Galosys.Foundation.StackExchange.Redis@26.5.20.1
#addin nuget:?package=Galosys.Foundation.StackExchange.Redis&version=26.5.20.1Install as a Cake Addin
#tool nuget:?package=Galosys.Foundation.StackExchange.Redis&version=26.5.20.1Install as a Cake Tool
成熟度: 🟢 稳定 — 生产可用,活跃维护
Galosys.Foundation.StackExchange.Redis 基于 StackExchange.Redis 提供完整的 IRedisConnection 实现,包括分布式缓存、分布式锁、幂等性控制、Pub/Sub 消息、自动重试和健康检查,适用于 ASP.NET Core 项目。
StackExchangeRedisCache(IDistributedCache)dotnet add package Galosys.Foundation.StackExchange.Redis
{
"ConnectionStrings": {
"Redis": "localhost:6379,abortConnect=false" // 单节点,最小配置
}
}
{
"Redis": {
"Connection": {
"ConnectionString": "localhost:6379,abortConnect=false", // 连接字符串
"ServiceName": "mymaster", // Sentinel 服务名称,哨兵模式下使用
"Password": "", // 密码,为空则不设置
"ConnectTimeout": 5000, // 连接超时(毫秒)
"SyncTimeout": 5000, // 同步操作超时(毫秒)
"AsyncTimeout": 10000, // 异步操作超时(毫秒)
"AbortOnConnectFail": false, // 连接失败时不中止,后台重连
"ConnectRetry": 3, // 初始连接重试次数
"KeepAlive": 60, // 保持活跃间隔(秒)
"Retry": {
"MaxRetries": 3, // 命令失败最大重试次数
"InitialDelayMs": 200, // 首次重试延迟(毫秒)
"MaxDelayMs": 3000, // 最大重试延迟(毫秒)
"EnableJitter": true // 启用随机抖动,防止惊群
}
}
}
}
配置优先级:
Redis:Connection>ConnectionStrings:Redis,向后兼容旧配置格式。
// 最小化配置 — 从 IConfiguration 读取
services.AddStackExchangeRedis(Configuration);
public class CacheService
{
private readonly RedisTemplate _redis;
public CacheService(RedisTemplate redis)
{
_redis = redis;
}
public async Task SetOrderAsync(string orderNo, Order order)
{
await _redis.OpsForValue().SetAsync($"order:{orderNo}", order, TimeSpan.FromMinutes(30));
}
public async Task<Order> GetOrderAsync(string orderNo)
{
return await _redis.OpsForValue().GetAsync<Order>($"order:{orderNo}");
}
public async Task<bool> DeleteOrderAsync(string orderNo)
{
return await _redis.DeleteAsync($"order:{orderNo}");
}
}
public class RawRedisService
{
private readonly IRedisConnection _connection;
public RawRedisService(IRedisConnection connection)
{
_connection = connection;
}
public async Task SetRawAsync(string key, byte[] value)
{
await _connection.StringSetAsync(Encoding.UTF8.GetBytes(key), value);
}
}
public class DistributedCacheService
{
private readonly IDistributedCache _cache;
public DistributedCacheService(IDistributedCache cache)
{
_cache = cache;
}
public async Task SetAsync(string key, string value)
{
await _cache.SetStringAsync(key, value, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
});
}
}
// Hash
await _redis.OpsForHash().PutAsync("user:001", "name", "张三");
await _redis.OpsForHash().PutAsync("user:001", "profile", new { Age = 25 });
var name = await _redis.OpsForHash().GetAsync<string>("user:001", "name");
// List
await _redis.OpsForList().RightPushAsync("task:queue", new TaskItem { Id = 1 });
var task = await _redis.OpsForList().LeftPopAsync<TaskItem>("task:queue");
// Set
await _redis.OpsForSet().AddAsync("tags:product:001", "电子产品", "手机");
var tags = await _redis.OpsForSet().MembersAsync<string>("tags:product:001");
// SortedSet
await _redis.OpsForZSet().AddAsync("leaderboard", "player:001", 9500);
var top10 = await _redis.OpsForZSet().ReverseRangeAsync<string>("leaderboard", 0, 9);
// Geo
await _redis.OpsForGeo().AddAsync("locations", 116.397, 39.908, "北京天安门");
var nearby = await _redis.OpsForGeo().RadiusAsync("locations", 116.397, 39.908, 10, GeoUnit.Kilometers);
// Stream
var msgId = await _redis.OpsForStream().AddAsync("events", new Dictionary<string, string> { ["type"] = "order" });
await _redis.OpsForStream().CreateConsumerGroupAsync("events", "my-group");
var messages = await _redis.OpsForStream().ReadGroupAsync("events", "my-group", "consumer-1", count: 10);
基于 Lua 原子脚本实现,支持看门狗自动续期,推荐使用 await using 自动释放:
public class PaymentService(IDistributedLock @lock)
{
public async Task PayAsync(string orderNo)
{
// 尝试获取锁,支持等待超时和自动续期
await using var handle = await @lock.TryAcquireAsync(
$"lock:pay:{orderNo}",
expiry: TimeSpan.FromSeconds(30), // 锁过期时间
waitTimeout: TimeSpan.FromSeconds(5), // 等待获取锁的超时
renewalInterval: TimeSpan.FromSeconds(10)); // 看门狗续期间隔
if (!handle.IsAcquired)
throw new BusinessException("获取锁失败");
// 业务逻辑...
}
}
防止重复请求,自动缓存成功结果:
public class OrderService(IDistributedIdempotence idempotence)
{
public async Task<OrderResult> CreateOrderAsync(string requestId, Order order)
{
// 原子标记请求为处理中
if (!await idempotence.TryMarkProcessingAsync(requestId, TimeSpan.FromMinutes(10)))
{
// 已有成功结果,直接返回缓存
var cached = await idempotence.GetCachedResultAsync(requestId);
if (cached != null) return JsonSerializer.Deserialize<OrderResult>(cached);
throw new BusinessException("请求正在处理中");
}
try
{
var result = await DoCreateOrderAsync(order);
// 标记成功并缓存结果
await idempotence.MarkSuccessAsync(requestId, JsonSerializer.Serialize(result), TimeSpan.FromHours(24));
return result;
}
catch
{
// 业务失败,清理状态允许重试
await idempotence.ClearStateAsync(requestId);
throw;
}
}
}
// 使用 RedisTemplate 发布
await redisTemplate.ConvertAndSendAsync("order.events", new OrderEvent { OrderNo = "001" });
// 实现消息监听器
public class OrderEventListener : IMessageListener
{
public async Task OnMessageAsync(RedisMessage message)
{
Console.WriteLine($"Channel={message.Channel}");
}
}
// 注册监听器
var container = serviceProvider.GetRequiredService<IRedisMessageListenerContainer>();
container.AddMessageListener(new OrderEventListener(), "order.events");
通过 ResilientRedisConnection 装饰器自动为所有 Redis 命令提供重试能力:
InitialDelayMs × 2^(attempt-1)TimeoutException、连接异常等自动重试IRedisConnection 接口不变,业务代码无需修改配置项参见上方 Retry 节点。
注册服务后自动注册基于 PING 的健康检查:
services.AddStackExchangeRedis(Configuration);
// 自动注册,无需额外配置
builder.Services.AddHealthChecks()
.AddCheck<RedisHealthCheck>("redis");
| 类 | 说明 |
|---|---|
StackExchangeRedisConnection |
IRedisConnection 实现,封装 ConnectionMultiplexer + IDatabase |
ResilientRedisConnection |
重试装饰器,指数退避 + 随机抖动 |
StackExchangeDistributedLock |
分布式锁实现(Lua 原子脚本 + 看门狗续期) |
StackExchangeDistributedIdempotence |
幂等性保证实现(原子标记 + 结果缓存) |
StackExchangeMessageListenerContainer |
Pub/Sub 消息监听容器,支持多频道多监听器 |
StackExchangeConnectionLoggerExtensions |
连接事件日志扩展(断开/恢复/错误) |
StackExchangeScriptExecutor |
Lua 脚本执行器,基于 LuaScript.Prepare |
StackExchangeRedisCli |
[Obsolete] 旧版客户端,保持兼容 |
IDatabaseExtensions |
StackExchange.Redis IDatabase 扩展方法 |
AddStackExchangeRedis(IConfiguration) 注册以下服务:
| 服务 | 实现 | 生命周期 |
|---|---|---|
ConnectionMultiplexer |
从配置创建 | Singleton |
IRedisConnection |
ResilientRedisConnection(StackExchangeRedisConnection) |
Singleton |
RedisTemplate |
RedisTemplate(基类) |
Singleton |
IDistributedCache |
StackExchangeRedisCache |
Singleton |
IDistributedLock |
StackExchangeDistributedLock |
Singleton |
IDistributedIdempotence |
StackExchangeDistributedIdempotence |
Singleton |
RedisConnectionLogger |
连接事件日志记录器 | Singleton |
RedisHealthCheck |
PING 健康检查 | Singleton |
| 特性 | FreeRedis | StackExchange.Redis |
|---|---|---|
| Pipeline | ✅ | ✅ |
| 分布式锁 | ✅ | ✅ |
| 幂等性 | ✅ | ✅ |
| Pub/Sub | ✅ | ✅ |
| 集群/哨兵 | ✅ | ✅ |
| IDistributedCache | ✅ | ✅ |
| 消息队列 (Stream) | ✅ | ❌ 不支持 |
| 重试装饰器 | ✅ | ✅ |
| 健康检查 | ✅ | ✅ |
| Lua 脚本执行器 | ✅ | ✅ |
| Transaction | ✅ | ✅ |
| Key 过期监听 | ✅ | ✅ |
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 net8.0 is compatible. net8.0-android net8.0-android was computed. net8.0-browser net8.0-browser was computed. net8.0-ios net8.0-ios was computed. net8.0-maccatalyst net8.0-maccatalyst was computed. net8.0-macos net8.0-macos was computed. net8.0-tvos net8.0-tvos was computed. net8.0-windows net8.0-windows was computed. net9.0 net9.0 was computed. net9.0-android net9.0-android was computed. net9.0-browser net9.0-browser was computed. net9.0-ios net9.0-ios was computed. net9.0-maccatalyst net9.0-maccatalyst was computed. net9.0-macos net9.0-macos was computed. net9.0-tvos net9.0-tvos was computed. net9.0-windows net9.0-windows was computed. net10.0 net10.0 was computed. net10.0-android net10.0-android was computed. net10.0-browser net10.0-browser was computed. net10.0-ios net10.0-ios was computed. net10.0-maccatalyst net10.0-maccatalyst was computed. net10.0-macos net10.0-macos was computed. net10.0-tvos net10.0-tvos was computed. net10.0-windows net10.0-windows was computed. |
This package is not used by any NuGet packages.
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 26.5.20.1 | 95 | 5/20/2026 |
| 26.5.19.1 | 97 | 5/19/2026 |
| 26.5.18.1 | 92 | 5/18/2026 |
| 26.5.15.1 | 96 | 5/15/2026 |
| 26.5.12.3 | 92 | 5/12/2026 |
| 26.5.12.2 | 93 | 5/12/2026 |
| 26.4.27.1-rc1 | 92 | 4/26/2026 |
| 26.4.25.1-rc1 | 90 | 4/25/2026 |
| 26.4.22.2-rc7 | 99 | 4/22/2026 |
| 26.4.22.2-rc6 | 86 | 4/22/2026 |
| 26.4.22.2-rc4 | 94 | 4/22/2026 |
| 26.4.12.8-rc1 | 100 | 4/12/2026 |
| 26.4.12.7-rc1 | 95 | 4/12/2026 |
| 26.1.30.1-rc1 | 126 | 1/30/2026 |
| 26.1.29.1 | 129 | 1/29/2026 |
| 26.1.28.5 | 130 | 1/28/2026 |
| 26.1.28.4 | 125 | 1/28/2026 |
| 26.1.28.2 | 125 | 1/28/2026 |
| 26.1.23.6 | 119 | 1/23/2026 |
| 26.1.21.1 | 114 | 1/21/2026 |