Azure上托管的ASP.NET Core App中Redis连接中的错误 [英] Error in Redis Connection in ASP.NET Core App Hosted on Azure
问题描述
我们在使用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屋!