使用 StackExchange.Redis 在 C# 中开始使用 Redis

Redis温故知新

一、定义

Redis(Remote Dictionary Server)是一个开源的、内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。Redis 支持多种类型的数据结构,如字符串(strings)、哈希表(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)与位图(bitmaps)、超日志(hyperloglogs)和地理空间(geospatial)索引半径查询等。Redis 具备丰富的特性,包括事务、发布/订阅、Lua 脚本、持久化、主从复制、哨兵(Sentinel)和集群(Cluster)等。

Redis 的主要特点和优势包括:

  1. 高性能:Redis 将数据存储在内存中,因此读写速度非常快,远超过传统的基于磁盘的数据库。
  2. 丰富的数据类型:Redis 支持多种数据类型,使得开发者可以非常灵活地处理各种数据结构和场景。
  3. 原子操作:Redis 的所有操作都是原子性的,这意味着多个客户端同时操作同一个数据项时,Redis 可以保证操作的串行化。
  4. 事务支持:Redis 提供了简单的事务支持,通过 MULTI、EXEC、DISCARD 和 WATCH 命令来实现。
  5. 持久化:Redis 支持两种持久化方式,RDB(Redis Database)快照和 AOF(Append Only File)日志,可以保障数据的可靠性。
  6. 发布/订阅:Redis 提供了发布/订阅模式,使得数据可以在多个客户端之间实时共享。
  7. 高可用性和分布式:通过 Redis Sentinel 和 Redis Cluster,Redis 可以实现高可用性和分布式存储,确保数据的可用性和容错性。
  8. 简单和易用:Redis 的命令行界面简洁且功能强大,同时提供了丰富的客户端库,支持多种编程语言,如 Python、Java、C++ 等。

缺点:

  1. 内存限制:由于Redis将数据存储在内存中,因此其存储容量受到物理内存大小的限制。当数据量非常大时,可能会耗尽服务器的内存资源。
  2. 数据持久化的开销:虽然Redis提供了持久化功能,但RDB和AOF都会带来一定的性能开销。特别是在高负载的情况下,持久化可能会成为系统的瓶颈。
  3. 网络依赖:Redis是一个基于网络的数据库,客户端与服务器之间的通信需要通过网络进行。因此,Redis的性能和可靠性会受到网络状况的影响。
  4. 复杂的数据结构操作可能较慢:虽然Redis支持多种复杂的数据结构,但在某些情况下,对这些数据结构进行复杂操作(如深度遍历、复杂查询等)可能会比较慢,因为Redis并不是为这些操作而优化的。
  5. 单线程模型:Redis采用单线程模型来处理客户端的请求。虽然这保证了操作的原子性和简化了数据一致性的处理,但在高并发场景下,单个CPU核心可能成为性能瓶颈。不过,由于Redis的I/O操作是异步的,并且内存访问速度非常快,因此在实际应用中,Redis的性能通常仍然很高。

基本数据结构:

String(字符串):最基本的键值对类型,支持存储二进制数据。

List(列表):一个链表,可以从两端插入和弹出元素。

Set(集合):无序集合,适合去重。

Hash(哈希):键值对的集合,类似于一个字段集合。

Sorted Set(有序集合):和 Set 类似,但可以给每个元素附加一个分数,Redis 会根据分数排序。

Bitmap:一种用于处理二进制数据的结构。

HyperLogLog:用于估算基数(例如,去重统计)。

使用场景:

缓存:Redis 常被用作缓存,来加速对数据的访问,减少数据库的压力。

消息队列:Redis 支持发布/订阅模式,也可以用作轻量级的消息队列。

分布式锁:通过 SETNX(SET if Not eXists) 命令可以实现分布式锁。

会话存储:在 Web 应用中可以将用户的会话信息存储在 Redis 中,实现快速访问和持久化。

排行榜系统:利用 Redis 的有序集合可以快速实现排行榜功能。

基本命令:

键操作

  • SET key value:设置一个键值对。
  • GET key:获取某个键的值。
  • DEL key:删除一个键。
  • EXPIRE key seconds:为键设置过期时间。

列表操作

  • LPUSH key value:向列表左侧添加一个元素。
  • RPOP key:从列表右侧弹出一个元素。

集合操作

  • SADD key value:向集合添加元素。
  • SMEMBERS key:获取集合中的所有元素。

哈希操作

  • HSET key field value:为哈希表中的字段设置值。
  • HGET key field:获取哈希表中某个字段的值。

有序集合操作

  • ZADD key score member:添加一个带有分数的成员。
  • ZRANGE key start stop:按分数范围获取有序集合中的元素。

高级特性:

高可用与复制:

Redis 的高可用性依赖于主从复制(Replication)和哨兵(Sentinel)机制。

  • 主从复制:Redis 支持主从架构,数据可以自动从主节点复制到从节点,保证数据的冗余和高可用。主节点进行写操作,从节点作为备份并允许读取操作。这样在主节点失效时,可以提升从节点为主节点,避免数据丢失。

  • Redis Sentinel:是 Redis 的高可用解决方案,用于监控 Redis 集群中的主从节点。Sentinel 会定期检查 Redis 主节点的状态,发现主节点宕机时会自动进行主从切换。

    Sentinel 的职责:监控、通知、自动故障转移以及配置提供。

集群:

Redis Cluster 是 Redis 的分布式方案,允许将数据自动分片到多个 Redis 实例上。

  • 分片机制:Redis Cluster 将键值空间分为 16384 个槽,数据根据哈希分布在多个节点上。每个节点负责一部分槽位的数据存储。当一个节点出现故障时,集群可以通过冗余机制保持数据的可用性。
  • 节点故障检测和恢复:Redis Cluster 具备自动故障转移的功能,确保在部分节点失效时,数据仍然可用。

持久化机制:

Redis 的持久化保证即使在服务器重启或宕机时,数据也可以恢复。Redis 提供两种持久化方案:

  • RDB(Redis Database Backup):定期将数据的快照保存到磁盘,适用于不需要实时保存数据的场景。虽然它对性能的影响较小,但可能会导致数据丢失,因为只在指定时间点生成快照。
  • AOF(Append-Only File):记录每次写操作的日志,保证数据不丢失。Redis 可以通过定期对 AOF 文件进行压缩来减少磁盘空间的占用。AOF 相对较慢,但能够提供更强的数据安全性。

缓存过期策略:

  • LRU (Least Recently Used):最少使用算法,会优先删除最近最少使用的键。

  • LFU (Least Frequently Used):最少频率使用算法,会优先删除访问频率最低的键。

  • TTL (Time to Live):为键设置一个明确的过期时间,过期后自动删除。

使用 StackExchange.Redis 在 C# 中开始使用 Redis

在开始在 C# 中使用 Redis 之前,您需要安装 StackExchange.Redis 库。您可以使用 Visual Studio/Rider 中的 NuGet 包管理器或通过命令行来执行此操作。

Install-Package StackExchange.Redis

首先,让我们连接到 Redis 服务器。确保您有一个在默认端口 (6379) 上本地运行的 Redis 服务器。如果您的 Redis 服务器托管在其他地方,您可以调整连接参数。

class Program
{
    static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
         // 读取 Redis 连接字符串
        var redisConnectionString = builder.Configuration.GetValue<string>("RedisCacheConnectionString");
        // 注册 Redis 连接多路复用器
        builder.Services.AddSingleton<IConnectionMultiplexer>(
            ConnectionMultiplexer.Connect(string.IsNullOrEmpty(redisConnectionString) ? "localhost" : redisConnectionString));
    }
}
public interface ICacheService
{
    Task SetRedisByKey<T>(string key, T value, TimeSpan? expiry = null) where T: class;
    
    Task<T?> GetByKeyFromRedis<T>(string key) where T: class;
    
    Task RemoveByKeyFromRedis(string key);
}

public class CacheService : ICacheService
{
    private readonly IConnectionMultiplexer _connectionMultiplexer;

    public CacheService(IConnectionMultiplexer connectionMultiplexer)
    {
        _connectionMultiplexer = connectionMultiplexer;
    }
    
    public async Task SetRedisByKey<T>(string key, T value, TimeSpan? expiry = null) where T: class
    {
        if (value != null)
        {
            expiry ??= TimeSpan.FromMinutes(5);
            var stringValue = value as string ?? JsonConvert.SerializeObject(value);
            await _connectionMultiplexer.GetDatabase().StringSetAsync(key, stringValue, expiry).ConfigureAwait(false);
        }
    }
    
    public async Task<T?> GetByKeyFromRedis<T>(string key) where T: class
    {
        var cachedResult = await _connectionMultiplexer.GetDatabase().StringGetAsync(key).ConfigureAwait(false);
        return !cachedResult.IsNullOrEmpty
            ? typeof(T) == typeof(string) ? cachedResult.ToString() as T :
                JsonConvert.DeserializeObject<T>(cachedResult)
            : default;
    }
    
    public async Task RemoveByKeyFromRedis(string key)
    {
        var db = _connectionMultiplexer.GetDatabase();
        await db.KeyDeleteAsync(key);
    }
}

Redis 提供多种数据结构,如 StringHashListSetSorted Set 等。下面展示如何使用 StackExchange.Redis 操作这些数据结构:

1、操作字符串

// 设置一个字符串值
await _connectionMultiplexer.GetDatabase().StringSetAsync("name", "Alice");

// 获取字符串值
var name = await _connectionMultiplexer.GetDatabase().StringGetAsync("name");

2、操作哈希 (Hash)

// 设置哈希字段
await _connectionMultiplexer.GetDatabase().HashSetAsync("user:1001", new HashEntry[]
{
    new HashEntry("name", "Alice"),
    new HashEntry("age", 30)
});

// 获取哈希字段的值
var name = await _connectionMultiplexer.GetDatabase().HashGetAsync("user:1001", "name");

3、操作列表 (List)

// 向列表的左侧添加元素
await _connectionMultiplexer.GetDatabase().ListLeftPushAsync("tasks", "Task 1");

// 从列表右侧弹出元素
var task = await _connectionMultiplexer.GetDatabase().ListRightPopAsync("tasks");

4、操作集合 (Set)

// 添加元素到集合
await _connectionMultiplexer.GetDatabase().SetAddAsync("skills", "C#");
await _connectionMultiplexer.GetDatabase().SetAddAsync("skills", "Redis");

// 获取集合中的所有元素
var skills = await _connectionMultiplexer.GetDatabase().SetMembersAsync("skills");

5、操作有序集合 (Sorted Set)

// 向有序集合添加元素及其分数
await  _connectionMultiplexer.GetDatabase().SortedSetAddAsync("leaderboard", "Alice", 1000);
await  _connectionMultiplexer.GetDatabase().SortedSetAddAsync("leaderboard", "Bob", 1500);

// 获取有序集合中前 10 名的成员
var topPlayers = await  _connectionMultiplexer.GetDatabase().SortedSetRangeByRankAsync("leaderboard", 0, 9);

参考文档

Getting Started with Redis in C# using StackExchange.Redis

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值