Подтвердить что ты не робот

StackExchange.Redis с Azure Redis необычно медленный или бросает ошибки таймаута

Я перемещаю весь существующий кеш-сервер Azure In-Role в Redis и решил использовать предварительный просмотр Azure Redis вместе с библиотекой StackExchange.Redis(https://github.com/StackExchange/StackExchange.Redis). Я написал для него весь код без особых проблем, но при запуске он абсолютно неэффективен и постоянно выдает ошибки таймаута (мой период таймаута установлен на 15 секунд).

Вот соответствующий код того, как я настраиваю соединение Redis и использую его для простых операций:

    private static ConnectionMultiplexer _cacheService;
    private static IDatabase _database;
    private static object _lock = new object();

    private void Initialize()
    {
        if (_cacheService == null)
        {
            lock (_lock)
            {
                if (_cacheService == null)
                {
                    var options = new ConfigurationOptions();
                    options.EndPoints.Add("{my url}", 6380);
                    options.Ssl = true;
                    options.Password = "my password";
                    // needed for FLUSHDB command
                    options.AllowAdmin = true;

                    // necessary?
                    options.KeepAlive = 30;
                    options.ConnectTimeout = 15000;
                    options.SyncTimeout = 15000;

                    int database = 0;

                    _cacheService = ConnectionMultiplexer.Connect(options);
                    _database = _cacheService.GetDatabase(database);
                }
            }
        }

    }

    public void Set(string key, object data, TimeSpan? expiry = null)
    {
        if (_database != null)
        {
            _database.Set(key, data, expiry: expiry);
        }
    }

    public object Get(string key)
    {
        if (_database != null)
        {
            return _database.Get(key);
        }
        return null;
    }

Выполнение очень простых команд, таких как "Получить" и "Установить часто", или выполнить 5-10 секунд. Похоже, что это сводит на нет всю цель использования его в качестве кеша, если он работает медленнее, чем фактическое получение реальных данных из моей базы данных:)

Я делаю что-то явно неправильное?

Изменить: вот некоторые статистические данные, которые я вытащил с сервера (с помощью Redis Desktop Manager) в случае, если кто-то проливает свет на что-либо.

Server
redis_version:2.8.12
redis_mode:standalone
os:Windows  
arch_bits:64
multiplexing_api:winsock_IOCP
gcc_version:0.0.0
process_id:2876

tcp_port:6379
uptime_in_seconds:109909
uptime_in_days:1
hz:10
lru_clock:16072421
config_file:C:\Resources\directory\xxxx.Kernel.localStore\1\redis_2092_port6379.conf

Clients
connected_clients:5
client_longest_output_list:0
client_biggest_input_buf:0
client_total_writes_outstanding:0
client_total_sent_bytes_outstanding:0
blocked_clients:0

Memory
used_memory:4256488
used_memory_human:4.06M
used_memory_rss:67108864
used_memory_rss_human:64.00M
used_memory_peak:5469760
used_memory_peak_human:5.22M
used_memory_lua:33792
mem_fragmentation_ratio:15.77
mem_allocator:dlmalloc-2.8

Persistence
loading:0
rdb_changes_since_last_save:72465
rdb_bgsave_in_progress:0
rdb_last_save_time:1408471440
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

Stats
total_connections_received:25266
total_commands_processed:123389
instantaneous_ops_per_sec:10
bytes_received_per_sec:275
bytes_sent_per_sec:65
bytes_received_per_sec_human:

Изменить 2. Вот методы расширения, которые я использую для Get/Set. Это очень простые методы, которые просто превращают объект в JSON и вызывают StringSet.

    public static object Get(this IDatabase cache, string key)
    {
        return DeserializeJson<object>(cache.StringGet(key));
    }

    public static void Set(this IDatabase cache, string key, object value, TimeSpan? expiry = null)
    {
        cache.StringSet(key, SerializeJson(value), expiry: expiry);
    }

Изменить 3: вот несколько примеров сообщений об ошибках:

    A first chance exception of type 'System.TimeoutException' occurred in StackExchange.Redis.dll
    Timeout performing GET MyCachedList, inst: 11, queue: 1, qu=1, qs=0, qc=0, wr=0/1, in=0/0

    A first chance exception of type 'System.TimeoutException' occurred in StackExchange.Redis.dll
    Timeout performing GET MyCachedList, inst: 1, queue: 97, qu=0, qs=97, qc=0, wr=0/0, in=3568/0
4b9b3361

Ответ 1

Вот рекомендуемая модель из Документация кэш-памяти Azure Redis:

private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() => {
    return ConnectionMultiplexer.Connect("mycache.redis.cache.windows.net,abortConnect=false,ssl=true,password=...");
});

public static ConnectionMultiplexer Connection {
    get {
        return lazyConnection.Value;
    }
}

Несколько важных моментов:

  • Он использует Lazy <T> для обработки инициализации без потоков
  • Он устанавливает "abortConnect = false", что означает, что если попытка первоначального подключения не удалась, ConnectionMultiplexer будет тихо повторять в фоновом режиме, а не исключать исключение.
  • Это свойство не проверяет свойство IsConnected, поскольку ConnectionMultiplexer будет автоматически повторять попытку в фоновом режиме, если соединение будет удалено.

Ответ 2

У меня были похожие проблемы. Кэш Redis был необычайно медленным, но он определенно кэшировался. В некоторых случаях для загрузки страницы потребовалось 20-40 секунд.

Я понял, что сервер кэша находится в другом месте, чем сайт. Я обновил кеш-сервер, чтобы жить в том же месте, что и на веб-сайте, и теперь все работает так, как ожидалось.

Эта же страница загружается через 4-6 секунд.

Удачи всем, кто имеет эти проблемы.

Ответ 3

Проблема заключается в том, как создается и используется объект подключения. мы столкнулись с точной проблемой изначально и исправлены с использованием одного объекта соединения, используемого во всех веб-запросах. И мы проверяем, является ли он нулевым или связанным в начале сеанса для изящного повторного создания объекта. которые исправили проблему.

Примечание: Также проверьте, в какой зоне Azure используется экземпляр Redis Cache и какая зона вашего веб-сервера существует. Лучше поддерживать как в той же зоне

В файле Global.ascx.cs

public static ConnectionMultiplexer RedisConnection;
public static IDatabase RedisCacheDb;

protected void Session_Start(object sender, EventArgs e)
    {
        if (ConfigurationManager.ConnectionStrings["RedisCache"] != null)
        {
            if (RedisConnection == null || !RedisConnection.IsConnected)
            {
                RedisConnection = ConnectionMultiplexer.Connect(ConfigurationManager.ConnectionStrings["RedisCache"].ConnectionString);
            }
            RedisCacheDb = RedisConnection.GetDatabase();
        }
    }

Ответ 4

В нашем случае проблема связана с использованием SSL-соединения. Вы показываете, что ваш менеджер рабочего стола работает на не-SSL-порту, но ваш код использует SSL.

Быстрый тест на нашем Azure redis без SSL, извлечение около 80 тыс. значений с помощью команды LRANGE (также с .net и StackExchange.Redis) в основном instand. Когда используется SSL, тот же запрос занимает 27 секунд.

WebApp: стандартный S2

Redis: стандартный 1 ГБ

Изменить: проверка SLOWLOG, сама Redis, по-видимому, натолкнула slowlog на то, что он занимает 14 мс, чтобы захватить строки, но это далеко не так, как перенос с поддержкой SSL. Мы получили премиальный Redis для обеспечения безопасности между Redis и веб-приложениями.

Ответ 5

Это сработало в моем случае. Не забудьте увеличить SyncTimeout. Значение по умолчанию - 1 секунда.

private static Lazy<ConnectionMultiplexer> ConnectionMultiplexerItem = new Lazy<ConnectionMultiplexer>(() =>
{
    var redisConfig = ConfigurationOptions.Parse("mycache.redis.cache.windows.net,abortConnect=false,ssl=true,password=...");

    redisConfig.SyncTimeout = 3000;

    return ConnectionMultiplexer.Connect(redisConfig);
});

Проверьте, есть ли у вас кэш лазурного доступа и клиент в том же регионе в Azure. Например, вы можете получать тайм-ауты, когда ваш кеш находится в Восточных США, но клиент находится на западе США, и запрос не завершается в течение синхронного времени, или вы можете получать таймауты, когда вы отлаживаете свою локальную машину разработки. Его настоятельно рекомендуется иметь кеш и клиент в той же области Azure. Если у вас есть сценарий для совершения перекрестных вызовов, вам нужно установить значение synctimeout на более высокое значение.

Подробнее: https://azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/