【问题标题】:Error in Redis Connection in ASP.NET Core App Hosted on AzureAzure 上托管的 ASP.NET Core 应用程序中的 Redis 连接错误
【发布时间】:2017-11-01 23:42:25
【问题描述】:

我们正面临 Redis 缓存问题,它导致我们的网站崩溃。

以下是我们的实现方式:

我们使用了以下连接字符串:

"*******.redis.cache.windows.net:6380,password=*****=,ssl=True,abortConnect=False"

我们创建了一个服务类:

using Microsoft.Extensions.Options;
using SarahahDataAccessLayer;
using StackExchange.Redis;
using System;

namespace Sarahah.Services
{
    public class RedisService
    {
        private static Lazy<ConnectionMultiplexer> lazyConnection;
        private readonly ApplicationSettings _settings;
        public RedisService(IOptions<ApplicationSettings> settings)
        {
            _settings = settings.Value;
            lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
            {
                return ConnectionMultiplexer.Connect(_settings.RedisConnection);
            });
        }



        public  ConnectionMultiplexer Connection
        {
            get
            {
                return lazyConnection.Value;
            }
        }
    }
}

然后在 Startup.cs 我使用以下内容:

services.AddSingleton<RedisService>();

然后在控制器中我们使用依赖注入并分配给多路复用器:

connectionMultiplexer = redisService.Connection;

这是我们从缓存中获取的方式:

 private async Task<string> GetFromCache(string key)
    {
        if (connectionMultiplexer.IsConnected)
        {
            var cache = connectionMultiplexer.GetDatabase();

                return await cache.StringGetAsync(key);
        }
        else
        {
            return null;
        }
    }

这就是我们删除的方式:

  private async Task DeleteFromCache(string subdomain)
    {

            if (connectionMultiplexer.IsConnected)
            {
                var cache = connectionMultiplexer.GetDatabase();
                await cache.KeyDeleteAsync(subdomain).ConfigureAwait(false);
            }
    }

这就是我们添加的方式:

 {
        if (connectionMultiplexer.IsConnected)
        {
            var cache = connectionMultiplexer.GetDatabase();

                TimeSpan expiresIn;
                // Search Cache
                if (key.Contains("-"))
                {
                    expiresIn = new TimeSpan(0, GetMessagesCacheExpiryMinutes, 0);
                }
                // User info cache
                else
                {
                    expiresIn = new TimeSpan(GetProfileCacheExpiryHours, 0, 0);
                }
                await cache.StringSetAsync(key, serializedData, expiresIn).ConfigureAwait(false);

        }

但是,我们收到以下错误: 没有可用于服务此操作的连接

虽然我们有很多用户,但我们在 Azure 门户中只看到很少的连接:

请注意,我们将 redis 缓存托管在网络应用的同一区域。

感谢您的支持。

【问题讨论】:

    标签: asp.net azure caching redis asp.net-core


    【解决方案1】:

    每次您的依赖注入调用实例化 RedisService 类时,您的代码最终都会为lazyConnection 分配一个新的Lazy&lt;ConnectionMultiplexer&gt;,从而导致新连接以及连接泄漏,因为您没有调用 Close() 或 Dispose( ) 在旧的lazyConnection 上。

    尝试像这样更改您的代码:

    在 Startup.cs 中:

    public void ConfigureServices(IServiceCollection services)
            {
                // Add framework services.
                .........<whatever you have here>
                services.AddSingleton<RedisService>();
                services.Configure<ApplicationSettings>(options => Configuration.GetSection("ApplicationSettings").Bind(options));
            }
    

    RedisService.cs

    public class RedisService
    {
        private readonly ApplicationSettings _settings;
        private static Lazy<ConnectionMultiplexer> lazyConnection;
        static object connectLock = new object();
    
        public RedisService(IOptions<ApplicationSettings> settings)
        {
            _settings = settings.Value;
            if (lazyConnection == null)
            {
                lock (connectLock)
                {
                    if (lazyConnection == null)
                    {
                        lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
                        {
                            return ConnectionMultiplexer.Connect(_settings.RedisConnection);
                        });
                    }
                }
            }
        }
    
        public static ConnectionMultiplexer Connection
        {
            get
            {
                return lazyConnection.Value;
            }
        }
    }
    

    ApplicationSettings.cs

    public class ApplicationSettings
        {
            public string RedisConnection { get; set; }
        }
    

    appsettings.json

    {
        "Logging": {
            "IncludeScopes": false,
            "LogLevel": {
                "Default": "Debug",
                "System": "Information",
                "Microsoft": "Information"
            }
        },
        "ApplicationSettings": {
            "RedisConnection": "yourcachename.redis.cache.windows.net:6380,password=yourpassword,ssl=True,abortConnect=False,syncTimeout=4000"
        }
    }
    

    HomeController.cs

    public class HomeController : Controller
        {
            private RedisService redisService;
            private ConnectionMultiplexer connectionMultiplexer;
            public HomeController(IOptions<ApplicationSettings> settings)
            {
                redisService = new RedisService(settings);
                connectionMultiplexer = RedisService.Connection;
            }
            public IActionResult Index()
            {
                AddToCache("foo1", "bar").GetAwaiter().GetResult();
    
                return View();
            }
    
            private async Task<string> GetFromCache(string key)
            {
                if (connectionMultiplexer.IsConnected)
                {
                    var cache = connectionMultiplexer.GetDatabase();
    
                    return await cache.StringGetAsync(key);
                }
                else
                {
                    return null;
                }
            }
    
            private async Task DeleteFromCache(string subdomain)
            {
                if (connectionMultiplexer.IsConnected)
                {
                    var cache = connectionMultiplexer.GetDatabase();
                    await cache.KeyDeleteAsync(subdomain).ConfigureAwait(false);
                }
            }
    
            private async Task AddToCache(string key, string serializedData)
            {
                var GetMessagesCacheExpiryMinutes = 5;
                var GetProfileCacheExpiryHours = 1;
                if (connectionMultiplexer.IsConnected)
                {
                    var cache = connectionMultiplexer.GetDatabase();
    
                    TimeSpan expiresIn;
                    // Search Cache
                    if (key.Contains("-"))
                    {
                        expiresIn = new TimeSpan(0, GetMessagesCacheExpiryMinutes, 0);
                    }
                    // User info cache
                    else
                    {
                        expiresIn = new TimeSpan(GetProfileCacheExpiryHours, 0, 0);
                    }
                    await cache.StringSetAsync(key, serializedData, expiresIn).ConfigureAwait(false);
    
                }
            }
    

    【讨论】:

    • 您好,非常感谢。但我注意到你提到: redisService = new RedisService(settings);什么是 redisService 变量?我们已将实现修改为以下内容: new RedisService(settings); connectionMultiplexer = RedisService.Connection;这就是你的意思吗?
    • 我尝试创建一个新变量 (redisService),但由于出现错误,我无法调用 redisService.connection。
    • 当我们使用我在第一列中提到的方式时,错误仍然显示。谢谢。
    • 我已经更新了上面的代码以拥有您需要的所有部分。我希望这会有所帮助。
    • 不幸的是,我得到:无法使用实例引用访问成员 RedisService.Connection,而是使用类型名称对其进行限定。 (在这一行:connectionMultiplexer = redisService.Connection;)
    猜你喜欢
    • 2017-10-30
    • 1970-01-01
    • 1970-01-01
    • 2022-07-07
    • 2017-09-24
    • 2018-06-22
    • 2019-03-30
    • 1970-01-01
    • 2017-01-13
    相关资源
    最近更新 更多