簡體   English   中英

帶有 Azure Redis 的 StackExchange.Redis 速度慢得無法使用或引發超時錯誤

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

我正在將所有現有的 Azure 角色內緩存使用轉移到 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;
    }

執行 Get 和 Set 等非常簡單的命令通常會超時或需要 5-10 秒才能完成。 如果它比從我的數據庫中實際獲取真實數據慢得多,它似乎否定了將其用作緩存的全部目的:)

我做的事情明顯不正確嗎?

編輯:以下是我從服務器(使用 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:

編輯 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

以下是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會在后台自動重試。

我遇到了類似的問題。 Redis 緩存異常緩慢,但絕對是緩存。 在某些情況下,加載頁面需要 20-40 秒。

我意識到緩存服務器與站點的位置不同。 我將緩存服務器更新為與網站位於同一位置,現在一切正常。

同一個頁面現在在 4-6 秒內加載。

祝遇到這些問題的其他人好運。

問題是如何創建和使用連接對象。 我們最初遇到了確切的問題,並通過在所有 Web 請求中使用的單個連接對象進行了修復。 並且我們檢查它是否為空或在會話開始時連接以優雅地重新創建對象。 解決了這個問題。

注意:還要檢查您的 Redis 緩存實例正在運行的 Azure 區域以及您的 Web 服務器存在的區域。 最好將兩者都保持在同一區域

在 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();
        }
    }

在我們的例子中,問題在於使用 SSL 連接時。 您顯示您的桌面管理器正在非 SSL 端口上運行,但您的代碼正在使用 SSL。

在沒有 SSL 的情況下對我們的 Azure redis 進行快速基准測試,使用LRANGE命令(也使用 .net 和 StackExchange.Redis)檢索大約 80k 值基本上是即時的。 使用 SSL 時,相同的查詢需要 27 秒。

  • 網絡應用程序:標准 S2

  • Redis:標准 1 GB

編輯:檢查SLOWLOG ,Redis 本身似乎實際上達到了慢日志,抓取行需要 14 毫秒左右的時間,但這與啟用 SSL 的實際傳輸相去甚遠。 我們最終得到了一個高級 Redis,以在 Redis 和 Web 應用程序之間提供某種安全性。

它在我的情況下有效。 不要忘記增加 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 Redis 緩存和客戶端是否在 Azure 中的同一區域。 例如,當您的緩存在美國東部但客戶端在美國西部並且請求未在同步超時時間內完成時,您可能會超時,或者當您從本地開發機器進行調試時可能會超時。 強烈建議將緩存和客戶端放在同一 Azure 區域中。 如果您有執行跨區域調用的方案,您可能希望將同步超時設置為更高的值。

閱讀更多: 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