StackExchange.Redis.RedisConnectionException: System.OutOfMemoryException: - PullRequest
0 голосов
/ 11 февраля 2019

Я пытаюсь сохранить все свои статические значения времени выполнения в 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();
 }
...