Redis实践之高级用法:管道、消息队列、事务、分布式锁

一、概念与简介:

  1. 管道(Pipeline)的使用

    • 使用 CreateBatch 方法创建一个批处理对象。
    • 将多个操作添加到批处理中,然后执行批处理以提高性能。
  2. 发布-订阅模式(Pub/Sub)的实现

    • 使用 GetSubscriber 方法获取订阅者对象。
    • 使用 PublishAsync 方法发布消息。
    • 使用 SubscribeAsync 方法订阅频道并处理接收到的消息。
  3. 事务(Transaction)的应用

    • 使用 CreateTransaction 方法创建一个事务对象。
    • 将多个操作添加到事务中,然后执行事务以确保原子性。
  4. 分布式锁的实现

    • 使用 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 进行交互的核心组件。

作用

  1. 管理连接IConnectionMultiplexer 管理与 Redis 服务器的所有连接,包括连接池、连接复用等。

  2. 提供数据库操作接口:通过 GetDatabase 方法获取 IDatabase 对象,用于执行各种 Redis 命令。

  3. 发布-订阅功能:通过 GetSubscriber 方法获取 ISubscriber 对象,用于实现发布-订阅模式。

  4. 服务器管理:通过 GetServer 方法获取 IServer 对象,用于执行服务器级别的命令,如清空数据库、查看键空间等。

  5. 配置和监控:可以获取连接的配置信息,并提供一些监控和诊断功能

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 成为一个强大且灵活的内存数据库,广泛应用于缓存、会话管理、实时分析、消息队列等各种场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值