Redis Cache получает тайм-аут с запросами синхронизации и медленный ответ с асинхронными запросами только в асинхронном методе

Прежде всего, я использую службу Azure Redis Cache и клиент StackExchange.Redis(1.0.371) с моим приложением MVC 5 и Web Api 2. Я получаю очень интересное поведение. получение тайм-аута с запросами на синхронизацию и медленный ответ, когда я конвертирую свой синхронизирующий вызов с помощью async. Позвольте привести пример. Вот мой RedisCacheService,

public class RedisCacheService : ICacheService
{
    private readonly IDatabase _cache;
    private static readonly ConnectionMultiplexer ConnectionMultiplexer;

    static RedisCacheService()
    {

        var connection = ConfigurationManager.AppSettings["RedisConnection"];
        ConnectionMultiplexer = ConnectionMultiplexer.Connect(connection);
    }

    public RedisCacheService(ISettings settings)
    {            
        _cache = ConnectionMultiplexer.GetDatabase();
    }

    public bool Exists(string key)
    {
        return _cache.KeyExists(key);
    }

    public Task<bool> ExistsAsync(string key)
    {
        return _cache.KeyExistsAsync(key);
    }


    public void Save(string key, string value, int timeOutInMinutes)
    {
        var ts = TimeSpan.FromMinutes(timeOutInMinutes);
        _cache.StringSet(key, value, ts);
    }

    public Task SaveAsync(string key, string value, int timeOutInMinutes)
    {
        var ts = TimeSpan.FromMinutes(timeOutInMinutes);
        return _cache.StringSetAsync(key, value, ts);
    }

    public string Get(string key)
    {
        return _cache.StringGet(key);
    }

    public async Task<string> GetAsync(string key)
    {
        string result = null;
        var val = await _cache.StringGetAsync(key);
        if(val.HasValue) 
        {
            result = val;
        }
        return result;
    }

    ......................................................................
}

и вот мой метод, который вызывает кеш.

public async Task<IList<XX>> GetXXXXX(XXXX)
{
    var key = string.Format("{0}/XX{1}_{2}", XXXX, XX, XX);
    var xxx = _cacheService.Get(key);
    if (xxx != null)
    {
        return JsonConvert.DeserializeObject<IList<XX>>(xxx);
    }
    var x = await _repository.GetXXXXX(XXXXX);
    var contents = JsonConvert.SerializeObject(x);
    _cacheService.Save(key, JsonConvert.SerializeObject(x));
    return x;
}

Вышеупомянутый метод всегда дает мне,

System.TimeoutException
Timeout performing GET XXX, inst: 0, mgr: Inactive, queue: 3, qu=2, qs=1, qc=0, wr=1/1, in=0/0

or

System.TimeoutException
Timeout performing SETEX XXX, inst: 0, mgr: Inactive, queue: 2, qu=1, qs=1, qc=0, wr=1/1, in=0/0

Позвольте изменить его на асинхронный,

public async Task<IList<XX>> GetXXXXX(XXXX)
{
    var key = string.Format("{0}/XX{1}_{2}", XXXX, XX, XX);
    var xxx = await _cacheService.GetAsync(key);
    if (xxx != null)
    {
        return JsonConvert.DeserializeObject<IList<XX>>(xxx);
    }
    var x = await _repository.GetXXXXX(XXXXX);
    var contents = JsonConvert.SerializeObject(x);
    await  _cacheService.SaveAsync(key, JsonConvert.SerializeObject(x));
    return x;
}

Этот метод работает, но занимает не менее 5-10 секунд. Я имею в виду 10 секунд, если кеш недоступен, и 5 секунд, если кеш доступен.

Теперь давайте сделаем мой метод полностью синхронизированным,

public async Task<IList<XX>> GetXXXXX(XXXX)
{
    var key = string.Format("{0}/XX{1}_{2}", XXXX, XX, XX);
    var xxx = _cacheService.Get(key);
    if (xxx != null)
    {
        return Task.FromResult(JsonConvert.DeserializeObject<IList<XX>>(xxx));
    }
    //var x = await _repository.GetXXXXX(XXXXX);
    var x = (IList<XX>)new List<XX>();
    var contents = JsonConvert.SerializeObject(x);
    _cacheService.Save(key, JsonConvert.SerializeObject(x));
    return Task.FromResult(x);
}

Обратите внимание на комментарий для вызова метода репозитория. Вышеупомянутый метод работает мгновенно, то есть я получаю результат менее чем за 1 секунду. Явно что-то не так с клиентом Azure или StackExcahge.Redis.

Обновление: мой последний подход (асинхронный) также работает как шарм (быстро и без ошибок),

public async Task<IList<XX>> GetXXXXX(XXXX)
{
    var key = string.Format("{0}/XX{1}_{2}", XXXX, XX, XX);
    var xxx = await _cacheService.GetAsync(key);
    if (xxx != null)
    {
        return JsonConvert.DeserializeObject<IList<XX>>(xxx);
    }
    //var x = await _repository.GetXXXXX(XXXXX);
    var x = (IList<XX>)new List<XX>();
    var contents = JsonConvert.SerializeObject(x);
    await _cacheService.SaveAsync(key, JsonConvert.SerializeObject(x));
    return x;
}

Обратите внимание, что я все же прокомментировал код репозитория.


person user960567    schedule 31.12.2014    source источник
comment
Я не понимаю вопроса. В чем разница между вызовом кеша, который истекает по тайм-ауту (или занимает 5 секунд), и вызовом кеша, который возвращается быстро?   -  person Mike Harder    schedule 31.12.2014
comment
Разница в том, что _cacheService.Get(key)` и _cacheService.GetAsync(key)   -  person user960567    schedule 03.01.2015
comment
Не могли бы вы попытаться найти медленные запросы в Redis? В обычном Redis есть команды slowlog, но я не знаю о Azure.   -  person flaschenpost    schedule 28.03.2015


Ответы (2)


Похоже, что эти тайм-ауты в Azure могут быть открытой проблемой. Вы пробовали это? код против локального (не Azure) сервера? Вы получаете такие же результаты?

person XeroxDucati    schedule 09.01.2015
comment
Да, я видел эту ветку, и у меня установлена ​​последняя версия StackExchange.Redis. - person user960567; 10.01.2015

Я решил проблему тайм-аута в Redis Cache, установив свойство syncTimeout в строке подключения Redis Cache.

e.g. var conn = ConnectionMultiplexer.Connect("contoso5.redis.cache.windows.net,ssl=true,password=password,syncTimeout=5000");

Справочник по свойствам строки подключения https://stackexchange.github.io/StackExchange.Redis/Configuration

person Julius Depulla    schedule 08.11.2019