简体   繁体   English

带有 Azure Redis 的 StackExchange.Redis 速度慢得无法使用或引发超时错误

[英]StackExchange.Redis with Azure Redis is unusably slow or throws timeout errors

I'm moving all of my existing Azure In-Role cache use to Redis and decided to use the Azure Redis preview along with the StackExchange.Redis library ( https://github.com/StackExchange/StackExchange.Redis ).我正在将所有现有的 Azure 角色内缓存使用转移到 Redis,并决定将 Azure Redis 预览版与 StackExchange.Redis 库 ( https://github.com/StackExchange/StackExchange.Redis ) 一起使用。 I wrote all the code for it without much problem, but when running it is absolutely unusably slow and constantly throws timeout errors (my timeout period is set to 15 seconds).我为它编写了所有代码,没有太大问题,但是运行时它绝对慢得无法使用,并且不断抛出超时错误(我的超时时间设置为 15 秒)。

Here is the relevant code for how I am setting up the Redis connection and using it for simple operations:以下是我如何设置 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;
    }

Performing very simple commands like Get and Set often time out or take 5-10 seconds to complete.执行 Get 和 Set 等非常简单的命令通常会超时或需要 5-10 秒才能完成。 Seems like it kind of negates the whole purpose of using it as a cache if it's WAY slower than actually fetching the real data from my database :)如果它比从我的数据库中实际获取真实数据慢得多,它似乎否定了将其用作缓存的全部目的:)

Am I doing anything obviously incorrect?我做的事情明显不正确吗?

Edit : here are some stats that I pulled from the server (using Redis Desktop Manager) in case that sheds some light on anything.编辑:以下是我从服务器(使用 Redis 桌面管理器)提取的一些统计数据,以防万一。

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:

Edit 2 : Here are the extension methods I'm using for Get/Set -- they are very simple methods that just turn an object into JSON and call StringSet .编辑 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);
    }

Edit 3 : here are a couple example error messages:编辑 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

Here is the recommended pattern, from the Azure Redis Cache documentation :以下是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;
    }
}

A few important points:几个重要的点:

  • It uses Lazy<T> to handle thread-safe initialization它使用 Lazy<T> 来处理线程安全的初始化
  • It sets "abortConnect=false", which means if the initial connect attempt fails, the ConnectionMultiplexer will silently retry in the background rather than throw an exception.它设置“abortConnect=false”,这意味着如果初始连接尝试失败,ConnectionMultiplexer 将在后台静默重试而不是抛出异常。
  • It does not check the IsConnected property, since ConnectionMultiplexer will automatically retry in the background if the connection is dropped.检查IsConnected财产,因为如果连接中断ConnectionMultiplexer会在后台自动重试。

I was having similar issues.我遇到了类似的问题。 Redis cache was unusually slow but was definitely caching. Redis 缓存异常缓慢,但绝对是缓存。 In some cases, it took 20-40 seconds to load a page.在某些情况下,加载页面需要 20-40 秒。

I realized that the cache server was in a different location than the site's.我意识到缓存服务器与站点的位置不同。 I updated the cache server to live in the same location as the website and now everything works as expected.我将缓存服务器更新为与网站位于同一位置,现在一切正常。

That same page now loads in 4-6 seconds.同一个页面现在在 4-6 秒内加载。

Good luck to anyone else who's having these issues.祝遇到这些问题的其他人好运。

The problem is how the connection object created and used.问题是如何创建和使用连接对象。 we faced exact problem initially and fixed with a single connection object getting used across all web requests.我们最初遇到了确切的问题,并通过在所有 Web 请求中使用的单个连接对象进行了修复。 And we check is it null or connected in session start for graceful re creating object.并且我们检查它是否为空或在会话开始时连接以优雅地重新创建对象。 that fixed the issue.解决了这个问题。

Note: Also check in which Zone of Azure your Redis Cache instance is running and Which Zone your Web Server exist.注意:还要检查您的 Redis 缓存实例正在运行的 Azure 区域以及您的 Web 服务器存在的区域。 It is better to maintain both in Same Zone最好将两者都保持在同一区域

In Global.ascx.cs file在 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();
        }
    }

In our case the issue is when using SSL connection.在我们的例子中,问题在于使用 SSL 连接时。 You're showing that your desktop manager is running on the non-SSL port, but your code is using SSL.您显示您的桌面管理器正在非 SSL 端口上运行,但您的代码正在使用 SSL。

A quick benchmark on our Azure redis without SSL, retrieving around 80k values with an LRANGE command (also with .net and StackExchange.Redis) is basically instand.在没有 SSL 的情况下对我们的 Azure redis 进行快速基准测试,使用LRANGE命令(也使用 .net 和 StackExchange.Redis)检索大约 80k 值基本上是即时的。 When SSL is used, the same query takes 27 seconds.使用 SSL 时,相同的查询需要 27 秒。

  • WebApp: Standard S2网络应用程序:标准 S2

  • Redis: Standard 1 GB Redis:标准 1 GB

Edit: Checking the SLOWLOG , Redis itself seems to actually hit slowlog with it's 14ms time it takes or so to grab the rows, but this is far from the actual transfer with SSL enabled.编辑:检查SLOWLOG ,Redis 本身似乎实际上达到了慢日志,抓取行需要 14 毫秒左右的时间,但这与启用 SSL 的实际传输相去甚远。 We ended up with a premium Redis to have some sort of security between Redis and Web Apps.我们最终得到了一个高级 Redis,以在 Redis 和 Web 应用程序之间提供某种安全性。

It worked in my case.它在我的情况下有效。 Don't forget to increase the SyncTimeout.不要忘记增加 SyncTimeout。 The default is 1 second.默认值为 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);
});

Check if you your Azure Redis Cache and the Client in the same region in Azure.检查您的 Azure Redis 缓存和客户端是否在 Azure 中的同一区域。 For example, you might be getting timeouts when your cache is in East US but the client is in West US and the request doesn't complete in synctimeout time or you might be getting timeouts when you are debugging from your local development machinex.例如,当您的缓存在美国东部但客户端在美国西部并且请求未在同步超时时间内完成时,您可能会超时,或者当您从本地开发机器进行调试时可能会超时。 It's highly recommended to have the cache and in the client in the same Azure region.强烈建议将缓存和客户端放在同一 Azure 区域中。 If you have a scenario to do a cross region calls, you would want to set the synctimeout to a higher value.如果您有执行跨区域调用的方案,您可能希望将同步超时设置为更高的值。

Read more: https://azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/阅读更多: https : //azure.microsoft.com/en-us/blog/investigating-timeout-exceptions-in-stackexchange-redis-for-azure-redis-cache/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM