Я пытаюсь сохранить все свои статические значения времени выполнения в MemoryCache и Redis Cache.MemoryCache используется как локальный кеш, если значение кеша не доступно в локальном кеше для указанного кеш-ключа, оно будет извлекать и восстанавливать значение с сервера redis.А используя метод «PublishAsync» из StackExchange.Redis.IDatabaseAsync, я отправляю сообщение в указанный канал, чтобы сохранить значение локального кэша во всех других службах или экземплярах.
Проблема в том, что метод будет вызываться '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();
}