Azure上托管的ASP.NET Core App中Redis连接中的错误 [英] Error in Redis Connection in ASP.NET Core App Hosted on Azure

查看:80
本文介绍了Azure上托管的ASP.NET Core App中Redis连接中的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在使用Redis缓存时遇到了问题,这导致我们的网站崩溃.

We are facing problems with Redis caching and it's causing crashes in our site.

以下是我们的实现方式:

The following is how we implemented it:

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

We used the following connection string:

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

我们创建了一个服务类:

We created a service class:

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中,我使用以下内容:

Then in Startup.cs I use the following:

services.AddSingleton<RedisService>();

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

Then in controllers we use dependency injection and we assign to a multiplexer:

connectionMultiplexer = redisService.Connection;

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

This is how we get from the cache:

 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);

        }

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

However, we get the following error: No connection is available to service this operation

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

Although we have a lot of users, we only see few connections in Azure portal:

请注意,我们在Web应用程序的同一区域托管了Redis缓存.

Please note that we hosted the redis cache in the same region of the web app.

感谢您的支持.

推荐答案

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

Each time your dependency injection calls instantiates the RedisService class, your code ends up assigning a new Lazy<ConnectionMultiplexer> to lazyConnection, thus resulting in a new connection as well as a connection leak as you are not calling Close() or Dispose() on the old lazyConnection.

尝试像这样更改代码:

在Startup.cs中:

In 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

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

ApplicationSettings.cs

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

appsettings.json

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

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);

            }
        }

这篇关于Azure上托管的ASP.NET Core App中Redis连接中的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆