我正在尝试将我所有的运行时静态值存储到MemoryCache和Redis Cache中。 MemoryCache的用法类似于本地缓存,如果本地缓存中没有指定缓存键的缓存值,则它将从Redis服务器中获取并还原该值。通过使用StackExchange.Redis.IDatabaseAsync中的“ PublishAsync”方法,我将消息发布到给定的通道,以在所有其他服务或实例中保留本地缓存的值。
这里的问题是该方法将被称为'n'次以存储和获取缓存值,因此在实现此方案后,redis存储空间不足,并在AppInsights中记录以下引发的错误。我无法找出根本原因,“ PublishAsync”方法导致了问题或任何想法?
StackExchange.Redis.RedisConnectionException:
System.OutOfMemoryException: at System.Array.Resize (mscorlib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089)
at StackExchange.Redis.PhysicalConnection.EnsureSpaceAndComputeBytesToRead
(StackExchange.Redis.StrongName, Version=1.2.6.0, Culture=neutral,
PublicKeyToken=c219ff1ca8c2ce46) at
StackExchange.Redis.PhysicalConnection.BeginReading
(StackExchange.Redis.StrongName, Version=1.2.6.0, Culture=neutral,
PublicKeyToken=c219ff1ca8c2ce46) at
StackExchange.Redis.PhysicalConnection+<>c.<.cctor>b__104_0
(StackExchange.Redis.StrongName, Version=1.2.6.0, Culture=neutral,
PublicKeyToken=c219ff1ca8c2ce46)
以下是我设置缓存的方式,
public static void AddToCache<T>(TenantInfo tenant, string cacheKey, T result, bool isInteractiveUser = false, string hashKey = default(string), TimeSpan? specifiedExpirationTime = null, bool IsincludeMemoryCache = true)
{
try
{
var expiration = TimeSpan.FromMinutes(default(int));
if (specifiedExpirationTime != null)
expiration = specifiedExpirationTime.Value;
else
expiration = (isInteractiveUser && !IsRedisCachingEnabled) ? TimeSpan.FromMinutes(3) : TimeSpan.FromMinutes(lifetimeMinutes);
tenant = tenant ?? TenantInfo.GetTenantInfoForRequest();
if (IsincludeMemoryCache)
{
CacheValue cValue = ManageMemoryCache(tenant, cacheKey, result, hashKey, expiration, IsincludeMemoryCache);
PublishCacheData(tenant.TenantId, cacheKey, cValue, hashKey);
}
if (IsRedisCachingEnabled)
{
IDatabase redisCacheDb = Connection.GetDatabase();
if (redisCacheDb != null)
{
if (!string.IsNullOrWhiteSpace(hashKey))
{
redisCacheDb.HashSetAsync(FormatCacheKey(tenant.TenantId, hashKey), (CachePrefix + cacheKey), JsonConvert.SerializeObject(FormatCacheValue(expiration, result, IsincludeMemoryCache))).Forget();
redisCacheDb.KeyExpireAsync(FormatCacheKey(tenant.TenantId, hashKey), expiration).Forget();
}
else
{
redisCacheDb.StringSetAsync((CachePrefix + cacheKey), JsonConvert.SerializeObject(FormatCacheValue(expiration, result, IsincludeMemoryCache)), expiration).Forget();
}
}
}
}
catch (TimeoutException e)
{
AppInsightsRuntime.TelemetryClient.TrackTrace(e.Message, Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information);
// ignore, timeouts happen, not necessarily a problem. we'll just lay off of redis for a short while to allow it to cool down
tokenCacheFailures++;
if (tokenCacheFailures > 2)
{
tokenCachingDisabled = DateTimeOffset.Now.AddSeconds(30);
AppInsightsRuntime.TelemetryClient.TrackTrace("Disabling validate token cache for 30 seconds due to timeouts", Microsoft.ApplicationInsights.DataContracts.SeverityLevel.Information);
}
}
catch (Exception e)
{
LogCacheError(e);
}
}
这是发布缓存数据的方式,
private static void PublishCacheData(Guid tenantId, string cacheKey, CacheValue data, string hashKey)
{
if (!IsConnected) return;
IDatabase redisCacheDb = Connection.GetDatabase();
//Publish changes to redis to trigger update in all servers (in case of scale out)
//Will also write to memory cache if the object is not there
CacheSyncPayload payload = new CacheSyncPayload
{
HashKey = !string.IsNullOrWhiteSpace(hashKey) ? FormatCacheKey(tenantId, hashKey) : null,
CacheKeys = new[] { cacheKey },
NonHashedCacheKeys = null,
IsClearCache = false,
Payload = data
};
redisCacheDb.PublishAsync(string.Concat(CallbackChannel, tenantId.ToString()), JsonConvert.SerializeObject(payload)).Forget();
}