2017-06-29

StackExchange 連線 Redis 出現 Timeout

同事反應出現大量 Redis 連線 Timeout 的錯誤,因為 Redis 上存放 Sessoion 跟許多 config cache 資料,如果 Redis 異常會嚴重影響線上服務,所以立馬需要進行除錯

首先使用 Redis-cli 確認服務仍正常執行中,接著執行了 Redis Benchmark 檢查 server 回應,數據並沒有發現異常,使用 Redis Desktop Manager 連線 Redis 資料也可以正常取得,推測 Redis server 本身應該是正常的

接著確認同事的使用情境後發現並非全面性出現 Redis timeout 只有存取幾個特定的 key 會出現問題。仔細檢查後發現:引起 timeout error 的 key 都有 size 較大的特徵,推測可能是資料量太大造成的


錯誤訊息

2017-06-28 18:04:56,025 [17] [ERROR] [RedisObjectStore`1] 
Inner exception number - 0
Timeout performing HGETALL faqscache:******.portal.bll.appdatamanager+cachedata, inst: 1, queue: 18, qu: 0, qs: 18, qc: 0, wr: 0, wq: 0, in: 0, ar: 0, clientName: TestAPP01, serverEndpoint: 127.0.0.1:8188, keyHashSlot: 3414, IOCP: (Busy=0,Free=1000,Min=2,Max=1000), WORKER: (Busy=6,Free=8185,Min=2,Max=8191) (Please take a look at this article for some common client-side issues that can cause timeouts: http://stackexchange.github.io/StackExchange.Redis/Timeouts)
   at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor`1 processor, ServerEndPoint server)
   at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor`1 processor, ServerEndPoint server)
   at StackExchange.Redis.RedisDatabase.HashGetAll(RedisKey key, CommandFlags flags)
   at ******.Portal.BLL.Redis.RedisObjectStore`1.Get(String key)
Main exception & its inner exception Log end

解決方式

  • 修改資料同步 timeout 設定 - 放寬 syncTimeout 時間 (預設 1000 毫秒)
  1. 原始 redis 連線資訊
    public static class RedisConnectionFactory
    {
     private static readonly Lazy<ConnectionMultiplexer> Connection;
     public static IServer RedisServer;
     static RedisConnectionFactory()
     {
    
      var connectionString = "127.0.0.1:6379,127.0.0.1:6380,password=password";
          var options = ConfigurationOptions.Parse(connectionString);
    
      Connection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(options));
      RedisServer = GetConnection.GetServer(options.EndPoints.First());
     }
     public static ConnectionMultiplexer GetConnection => Connection.Value;
     public static IDatabase RedisDB => GetConnection.GetDatabase();
    }
    
  2. 修改後
    public static class RedisConnectionFactory
    {
     private static readonly Lazy<ConnectionMultiplexer> Connection;
     public static IServer RedisServer;
     static RedisConnectionFactory()
     {
    
      var connectionString = "127.0.0.1:6379,127.0.0.1:6380,password=password,syncTimeout =3000";
          var options = ConfigurationOptions.Parse(connectionString);
    
      Connection = new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(options));
      RedisServer = GetConnection.GetServer(options.EndPoints.First());
     }
     public static ConnectionMultiplexer GetConnection => Connection.Value;
     public static IDatabase RedisDB => GetConnection.GetDatabase();
    }
    

心得

放寬資料同步時間後,timeout 問題確實獲得解決,但還是建議同事從源頭端來縮小 redis 的資料量大小,一來減少 network 傳輸的 io ,二來可以增加 redis 回應速度

參考資訊

  1. StackExchange.Redis Configuration
  2. 使用StackExchange.Redis客戶端進行Redis訪問出現的Timeout異常排查

4 則留言:

  1. 能否提供一下RedisConnectionFactory的完整代碼及相關程式?

    回覆刪除
    回覆
    1. RedisConnectionFactory 完整程式已在內文中,相關程式指的是?

      刪除
  2. 解法不太對…
    修改設定值拉長time out時間會影響整台server
    建議做法是改成用pipeline的方式存取,Get改成GetAsync來避免阻塞問題
    然後再進一步縮小data,減少Network I/O

    回覆刪除
    回覆
    1. 大師說的是,感謝大師指導

      刪除