Redis实践之高级用法:管道、消息队列、事务、分布式锁
一、概念与简介:
-
管道(Pipeline)的使用:
- 使用
CreateBatch
方法创建一个批处理对象。 - 将多个操作添加到批处理中,然后执行批处理以提高性能。
- 使用
-
发布-订阅模式(Pub/Sub)的实现:
- 使用
GetSubscriber
方法获取订阅者对象。 - 使用
PublishAsync
方法发布消息。 - 使用
SubscribeAsync
方法订阅频道并处理接收到的消息。
- 使用
-
事务(Transaction)的应用:
- 使用
CreateTransaction
方法创建一个事务对象。 - 将多个操作添加到事务中,然后执行事务以确保原子性。
- 使用
-
分布式锁的实现:
- 使用
LockTakeAsync
方法尝试获取锁。 - 在获取锁后执行关键操作,并使用
LockReleaseAsync
方法释放锁。
- 使用
二、高级用法实践
1、首先,在你的 ASP.NET Core 项目中安装 StackExchange.Redis
包:
dotnet add package StackExchange.Redis
2、在Program.cs文件,配置redis服务接口
//注册redis 服务连接接口IConnectionMultiplexer
builder.Services.AddSingleton<IConnectionMultiplexer>(c =>
{
return ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis")??"localhost:6379");
});
3、appsetting.json文件,配置redis连接串
"ConnectionStrings": {
"Redis": "localhost:6379"
},
4、新增RedisServices.cs文件,实现高级用法
public class RedisServices
{
private readonly IConnectionMultiplexer _redis;
public RedisServices(IConnectionMultiplexer redis)
{
_redis = redis;
}
/// <summary>
/// redis 管道用法
/// </summary>
/// <returns></returns>
public async Task UsePipelineAsync()
{
var db = _redis.GetDatabase(3);
var batch = db.CreateBatch();
var tasks = new List<Task>();
for (int i = 0;i<100;i++)
{
_=batch.StringSetAsync($"key{i}", $"value{i}", TimeSpan.FromMinutes(1));
//tasks.Add(batch.StringSetAsync($"key{i}",$"value{i}",TimeSpan.FromMinutes(1)));
}
batch.Execute();
//await Task.WhenAll(tasks);
await Console.Out.WriteLineAsync("Pipeline execution completed.");
}
/// <summary>
/// redis 发布订阅用法:发布
/// </summary>
/// <param name="channel"></param>
/// <param name="message"></param>
/// <returns></returns>
public async Task PublishAsync(RedisChannel channel,string message)
{
var subscriber = _redis.GetSubscriber();
await subscriber.PublishAsync(channel, message);
Console.WriteLine($"Message '{message}' published to channel '{channel}'.");
}
//订阅
public async Task SubscriberAsync(RedisChannel channel)
{
var subscriber = _redis.GetSubscriber();
await subscriber.SubscribeAsync(channel, (ch,msg) =>
{
Console.WriteLine($"Received message '{msg}' from channel '{ch}'.");
});
}
/// <summary>
/// redis 事务用法
/// </summary>
/// <returns></returns>
public async Task UseTransactionAsync()
{
var db = _redis.GetDatabase(3);
var trans = db.CreateTransaction();
_=trans.StringSetAsync("key1", "new_value1");
_=trans.StringSetAsync("keyk", "new_valuek");
bool committed = await trans.ExecuteAsync();
Console.WriteLine($"Transaction committed: {committed}");
}
/// <summary>
/// redis 分布式锁用法
/// </summary>
/// <param name="lockkey"></param>
/// <returns></returns>
public async Task UseDistributedLockAsync(string lockkey)
{
var db = _redis.GetDatabase(3);
string lockvalue = Guid.NewGuid().ToString();
TimeSpan expiry = TimeSpan.FromMinutes(1);
bool acquired = await db.LockTakeAsync(lockkey,lockvalue,expiry);
if (acquired)
{
try
{
Console.WriteLine("Lock acquired, performing critical operation...");
// Perform critical operation here
}
finally
{
await db.LockReleaseAsync(lockkey,lockvalue);
Console.WriteLine("Lock released.");
}
}
else
{
Console.WriteLine("Failed to acquire lock.");
}
}
public async Task<bool> GetRedisLock()
{
var db = _redis.GetDatabase(3);
string lockkey = "_redisLock_";
string lockvalue = Guid.NewGuid().ToString();
TimeSpan expiry = TimeSpan.FromMinutes(1);
return await db.LockTakeAsync(lockkey, lockvalue, expiry);
}
}
5、注册RedisServices
//注册redis高级用法
builder.RegisterType<RedisServices>();
6、新建RedisController.cs
[Route("api/[controller]")]
[ApiController]
public class RedisController : ControllerBase
{
private readonly Repository.IRepository<Product> _repository;
private readonly RedisServices _redisServices;
public RedisController(Repository.IRepository<Product> repository,RedisServices redisServices)
{
_repository = repository;
_redisServices = redisServices;
}
//测试redis高级用法
[Route("UseRedis")]
[HttpPost]
public async Task<ActionResult> UseRedis()
{
//管道
await _redisServices.UsePipelineAsync();
//在 Redis 的发布/订阅(Pub/Sub)模式下,消息是即时传递的,这意味着消息只会发送给当前在线的订阅者。
//如果在发布消息时没有任何订阅者,那么这些消息将会丢失。因此,如果你在发布消息之后才开始订阅,之前发布的消息将不会被接收到。
RedisChannel channel = new("mychannel",RedisChannel.PatternMode.Literal);
await _redisServices.SubscriberAsync(channel);//先订阅
await _redisServices.PublishAsync(channel, "hello redis!");//再发布
//事务
await _redisServices.UseTransactionAsync();
//分布式锁
await _redisServices.UseDistributedLockAsync("distributeLock");
for (int i = 0;i<5000; i++)
{
bool acquired = await _redisServices.GetRedisLock();
if (acquired)
{
await Console.Out.WriteLineAsync($"第{i}次请求获取锁成功,并执行成功");
}
else
{
Thread.Sleep(1000);
}
}
return Ok();
}
}
三、代码详解
1、IConnectionMultiplexer
接口
IConnectionMultiplexer
是 StackExchange.Redis
库中的一个接口,代表了与 Redis 服务器的连接。它是使用 StackExchange.Redis
与 Redis 进行交互的核心组件。
作用
-
管理连接:
IConnectionMultiplexer
管理与 Redis 服务器的所有连接,包括连接池、连接复用等。 -
提供数据库操作接口:通过
GetDatabase
方法获取IDatabase
对象,用于执行各种 Redis 命令。 -
发布-订阅功能:通过
GetSubscriber
方法获取ISubscriber
对象,用于实现发布-订阅模式。 -
服务器管理:通过
GetServer
方法获取IServer
对象,用于执行服务器级别的命令,如清空数据库、查看键空间等。 -
配置和监控:可以获取连接的配置信息,并提供一些监控和诊断功能
2. 基于Redis的分布式锁
Redis提供了一种高效的分布式锁实现方式,通常使用 SETNX
命令(Set if Not Exists)和 EXPIRE
命令(设置过期时间)来实现。
- 获取锁:使用
SETNX
命令尝试设置一个键,如果键不存在则设置成功并返回1,否则返回0。然后使用EXPIRE
命令为该键设置一个过期时间,以防止死锁。 - 释放锁:删除该键即可释放锁。
3. 数据结构
Redis 支持多种数据结构,每种结构都有其特定的应用场景:
- 字符串(String):最基本的数据类型,可以存储任何形式的字符串,包括二进制数据。
- 哈希(Hash):适合存储对象,类似于 Python 的字典。
- 列表(List):有序集合,支持从两端进行操作,适合实现队列和栈。
- 集合(Set):无序集合,自动去重,适合做交集、并集、差集运算。
- 有序集合(Sorted Set):带权重的集合,元素有序排列,适合排行榜等场景。
四、总结
Redis 作为一个高性能的内存数据结构存储系统,具有许多优点,使其在各种应用场景中广受欢迎。以下是 Redis 的一些主要优点:
1. 高性能
-
低延迟:由于数据存储在内存中,读写操作非常快速,通常在毫秒级别。
-
高吞吐量:支持每秒数十万次的读写操作,非常适合高并发场景。
2. 丰富的数据结构
-
支持字符串、哈希、列表、集合、有序集合、位图(Bitmaps)、HyperLogLog 和地理位置(GEO)等多种数据结构,满足不同的应用需求。
3. 持久化
-
提供 RDB(快照)和 AOF(追加日志)两种持久化机制,可以根据需要选择合适的方式来保证数据的持久性。
4. 主从复制
-
支持主从复制,一个主节点可以有多个从节点,从节点可以分担读请求,提高系统的可用性和扩展性。
5. 高可用和自动故障转移
-
通过 Redis Sentinel 实现高可用性监控和自动故障转移,确保系统在节点故障时仍能正常运行。
-
Redis Cluster 提供了分布式解决方案,支持数据分片和自动故障转移,实现水平扩展。
6. 灵活的发布/订阅机制
-
支持发布/订阅模式,可以用于实时消息传递、通知系统等场景。
7. 脚本支持
-
内置 Lua 脚本支持,通过 EVAL 命令执行脚本,实现复杂的原子操作。
8. 缓存功能
-
提供多种缓存淘汰策略,如 LRU、LFU 等,可以根据需求选择合适的策略,优化内存使用。
9. 管道技术
-
支持管道技术,一次性发送多个命令,减少网络延迟,提高性能。
10. 易于使用
-
简单易懂的命令集和丰富的客户端库,支持多种编程语言,方便开发者快速上手。
11. 社区和生态系统
-
拥有活跃的开源社区和丰富的生态系统,提供了大量的工具和扩展,方便集成和管理。
12. 安全性
-
支持基于密码的访问控制和 SSL/TLS 加密通信,增强数据传输的安全性。
这些优点使得 Redis 成为一个强大且灵活的内存数据库,广泛应用于缓存、会话管理、实时分析、消息队列等各种场景。