全部產品
Search
文件中心

Tair:Tair用戶端重連指南

更新時間:Jun 30, 2024

由於受網路和運行環境的影響,應用程式可能會遇到暫時性的故障,例如瞬時的網路抖動、服務暫時不可用、服務繁忙導致逾時等。通過設計自動重試機制可以大幅避免此類故障,保障操作的成功執行。

引發暫時性故障的原因

原因

說明

故障觸發了高可用機制

雲原生記憶體資料庫Tair支援節點健康狀態監測,當監測到執行個體中的主節點不可用時,會自動觸發主備切換,例如將主節點和從節點進行互換,保障執行個體的高可用性。此時,用戶端可能會遇到下列暫時性故障:

  • 秒級的串連閃斷。

  • 30秒內的唯讀狀態(用於避免主備切換引起潛在的資料丟失風險和雙寫)。

說明

更多資訊,請參見主備切換

慢查詢引起了請求堵塞

執行時間複雜度為O(N)的操作,引發慢查詢和請求的堵塞,此時,用戶端發起的其他請求可能出現暫時性失敗。

複雜的網路環境

由於用戶端與Tair伺服器之間複雜網路環境引起,可能出現偶發的網路抖動、資料重傳等問題,此時,用戶端發起的請求可能會出現暫時性失敗。

推薦的重試準則

重試準則

說明

僅重試等冪的操作

由於逾時可能發生在下述任一階段:

  • 該命令由用戶端發送成功,但尚未到達Tair

  • 命令到達Tair,但執行逾時。

  • 命令在Tair中執行結束,但結果返回給用戶端時發生逾時。

如果執行重試可能導致某個操作在Tair中被重複執行,因此不是所有操作均適合設計重試機制。通常推薦僅重試等冪的操作,例如SET操作,即多次執行SET a b命令,那麼a的值只可能是b或執行失敗;如果執行LPUSH mylist a則不是等冪的,可能導致mylist中包含多個a元素。

適當的重試次數與間隔

根據業務需求和實際情境調整適當的重試次數與間隔,否則可能引發下述問題:

  • 如果重試次數不足或間隔太長,應用程式可能無法完成操作而導致失敗。

  • 如果重試次數過大或間隔過短,應用程式可能會佔用過多的系統資源,且可能因請求過多而堵塞在伺服器上無法恢複。

常見的稍候再試方式包括立即重試、固定時間重試、指數增加時間重試、隨機時間重試等。

避免重試嵌套

避免重試嵌套,否則可能會導致重複的重試且無法停止。

記錄重試異常並列印失敗報告

在重試過程中,建議在WARN層級上列印重試錯誤記錄檔,同時,僅在重試失敗時列印異常資訊。

Jedis

建議使用Jedis 4.0.0及以上版本,推薦使用最新的Jedis版本,以下代碼為Jedis 5.0.0的重試樣本。

  1. 添加Jedis的Pom依賴。

        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>5.0.0</version>
        </dependency>
  2. 重試程式碼範例。

    • 若執行個體為標準架構執行個體或叢集架構代理(Proxy)模式,需使用JedisPool模式。

      該樣本會將SET命令自動重試5次,且總重試時間不超過10s,每次重試之間等待類指數間隔的時間,如果最終不成功,則拋出異常。

      PooledConnectionProvider provider = new PooledConnectionProvider(HostAndPort.from("127.0.0.1:6379"));
      int maxAttempts = 5; // 最大重試次數
      Duration maxTotalRetriesDuration = Duration.ofSeconds(10); // 最大的重試時間
      UnifiedJedis jedis = new UnifiedJedis(provider, maxAttempts, maxTotalRetriesDuration);
      try {
          System.out.println("set key: " + jedis.set("key", "value"));
      } catch (Exception e) {
          // 表示嘗試maxAttempts次或到達了最大查詢時間maxTotalRetriesDuration仍舊沒有訪問成功。
          e.printStackTrace();
      }
    • 若執行個體為叢集架構直連模式,需使用JedisCluster模式。

      可以通過配置maxAttempts參數來定義失敗情況下的重試次數,預設值為5,如果最終不成功,則拋出異常。

      HostAndPort hostAndPort = HostAndPort.from("127.0.0.1:30001");
      int connectionTimeout = 5000;
      int soTimeout = 2000;
      int maxAttempts = 5;
      ConnectionPoolConfig config = new ConnectionPoolConfig();
      JedisCluster jedisCluster = new JedisCluster(hostAndPort, connectionTimeout, soTimeout, maxAttempts, config);
      try {
          System.out.println("set key: " + jedisCluster.set("key", "value"));
      } catch (Exception e) {
          // 表示嘗試maxAttempts之後仍舊沒有訪問成功。
          e.printStackTrace();
      }

Redisson

Redisson用戶端提供了兩個參數來控制重試邏輯:

  • retryAttempts:重試次數,預設為3。

  • retryInterval:稍候再試,預設為1,500毫秒。

重試樣本如下:

Config config = new Config();
config.useSingleServer()
    .setTimeout(1000)
    .setRetryAttempts(3)
    .setRetryInterval(1500) //ms
    .setAddress("redis://127.0.0.1:6379");
RedissonClient connect = Redisson.create(config);

StackExchange.Redis

StackExchang.Redis用戶端目前僅支援重試時串連,重試樣本如下:

var conn = ConnectionMultiplexer.Connect("redis0:6380,redis1:6380,connectRetry=3");
說明

如需實現API層級的重試策略,請參見Polly

Lettuce

Lettuce用戶端未提供在命令逾時後重試的參數,但是您可以通過下述參數來實現命令重試策略:

  • at-most-once execution:命令最多執行1次,即0次或1次,如果串連斷開並重新串連,命令可能會丟失。

  • at-least-once execution(預設):最少成功執行1次,即可能會在執行時進行多次嘗試,保障最少成功執行1次。使用此策略時,如果Tair執行個體發生了主備切換,此時用戶端可能累積了較多的重試命令,主備切換完成後可能會引發Tair執行個體的CPU使用率激增。

說明

更多資訊,請參見Client-OptionsCommand execution reliability

重試樣本:

clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE;