redis - 处理 Azure Redis 缓存异常

标签 redis stackexchange.redis azure-redis-cache

我正在使用 Azure Redis 缓存进行开发,并想验证我处理异常的方式。根据最佳实践,可能会遇到 RedisConnectionExceptions 并解决此问题,我们必须处理旧的 ConnectionMultiplexer 并创建一个新的。如果将 abortConnect 设置为 false,则多路复用器将在不抛出错误的情况下静默重试连接。因此,如果抛出异常,它只会在尝试重新连接但仍然失败后才发生。我对此的理解正确吗? 这是我的连接字符串 -

cachename.redis.cache.windows.net:6380,password=Password,ssl=True,abortConnect=False

我相信连接异常只会在您尝试在多路复用器上调用 GetConnection() 时发生。在下面找到我的代码 -

    static Lazy<ConnectionMultiplexer> multiplexer = CreateMultiplexer();

    public static ConnectionMultiplexer GetConnection() => multiplexer.Value;

    private static Lazy<ConnectionMultiplexer> CreateMultiplexer()
    {
        return new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
    }

    private static void CloseMultiplexer(Lazy<ConnectionMultiplexer> oldMultiplexer)
    {
        if (oldMultiplexer != null)
        {
            oldMultiplexer.Value.Close();
        }
    }

    public static void Reconnect()
    {
        var oldMultiplexer = multiplexer;
        CloseMultiplexer(multiplexer);
        multiplexer = CreateMultiplexer();
    }

我将在下面的另一个类中使用它 -

    public class RedisCacheManager
    {
        private static IDatabase _cache;

        private TimeSpan expiry = new TimeSpan(hours: 6, minutes: 0, seconds: 0);

        public RedisCacheManager()
        {
            try
            {
                _cache = RedisCacheHelper.GetConnection().GetDatabase();
            }
            catch(RedisConnectionException)
            {
                RedisCacheHelper.Reconnect();
                new RedisCacheManager();
            }
        }

        public async Task<RedisValue[]> GetFromCacheAsync(List<string> keys)
        {
            var cacheValues = await _cache.StringGetAsync(keys.Select(k => (RedisKey)k).ToArray());
            return cacheValues;
        }

        public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
        {
            var tasks = new List<Task>();

            foreach(var kvp in kvps)
            {
                tasks.Add(_cache.StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), expiry));
            }
            await Task.WhenAll(tasks);
        }
        }

我不确定在 catch block 中调用构造函数是否是一个好习惯。在调用 StringGetAsync 和 StringSetAsync 时,是否还有我需要处理的任何其他异常?

最佳答案

CacheManager 可以是这样的:

using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public sealed class RedisCacheManager : IDisposable
{
    private readonly TimeSpan _expiry;

    private readonly Lazy<ConnectionMultiplexer> _lazyConnection;

    private ConnectionMultiplexer Connection { get => _lazyConnection.Value; }

    public RedisCacheManager(string connectionString, TimeSpan expiry)
    {
        _expiry = expiry;

        _lazyConnection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
    }

    public async Task<RedisValue[]> GetFromCacheAsync(IEnumerable<string> keys)
    {
        var cacheValues = await Connection.GetDatabase()
          .StringGetAsync(keys.Select(key => (RedisKey)key).ToArray()).ConfigureAwait(false);
        return cacheValues;
    }

    public async Task SaveInCacheAsync<TValue>(Dictionary<string, TValue> kvps)
    {
        var tasks = kvps
            .Select(kvp => Connection.GetDatabase().StringSetAsync(kvp.Key, JsonConvert.SerializeObject(kvp), _expiry))
            .ToArray();

        await Task.WhenAll(tasks).ConfigureAwait(false);
    }

    public void Dispose()
    {
        if (_lazyConnection.IsValueCreated)
        {
            _lazyConnection.Value.Dispose();
        }
    }
}

使用:

public readonly static RedisCacheManager RedisCacheManager = new RedisCacheManager("connection string", TimeSpan.FromHours(6));

备注:

  • abortConnect=false(这意味着即使未建立与 Azure Cache for Redis 的连接,调用也会成功)和构造函数不应抛出任何异常Redis-异常

  • 从 GetDatabase 返回的对象是一个 cheap pass-thru object ,不需要存储。

  • GetFromCacheAsync/SaveInCacheAsync - 方法可以向外部抛出异常,这没问题。您可以申请Retry-policy解决 transient 故障。

  • 如果您有任何 IoC 容器,那么它应该创建具有单个实例范围的 RedisCacheManager(例如,Autofac registration)

关于redis - 处理 Azure Redis 缓存异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56143573/

相关文章:

asp.net - 通过 StackExchange.Redis 连接到 Redis 服务

c# - 使用 StackExchange.Redis 从 Redis 获取多个哈希值

c# - 从Azure Redis缓存插入或删除值时,是否需要在代码级别进行同步?

asp.net - 为什么 asp.net 上的 Azure Redis 缓存仅使用 1000 个连接的客户端并抛出超时错误?

azure - Delphi 连接到 Azure Redis 缓存

redis - 使用Redis的MultiPublisher-MultiConsumer队列

c# - Redis 偶尔挂起

node.js - 在 NodeJs 中合并一个非常大的列表的最佳方法是什么?

async-await - 如何在模拟的异步方法上设置可验证的期望?

queue - 获取Redis列表项索引