受網(wǎng)絡和運行環(huán)境影響,應用程序可能遇到暫時性故障,如瞬時網(wǎng)絡抖動、服務暫時不可用、服務繁忙導致超時等。 自動重試機制可大幅避免此類故障,保障操作成功執(zhí)行。
1 引發(fā)暫時性故障的原因
1.1 故障觸發(fā)了高可用機制
云 Redis 支持節(jié)點健康狀態(tài)監(jiān)測,當監(jiān)測到實例中的主節(jié)點不可用時,會自動觸發(fā)主備切換,例如將主節(jié)點和從節(jié)點進行互換,保障實例的高可用性。此時,客戶端可能會遇到下列暫時性故障:秒級的連接閃斷。30 秒內(nèi)的只讀狀態(tài)(用于避免主備切換引起潛在的數(shù)據(jù)丟失風險和雙寫)。 更多參見:主備切換(https://help.aliyun.com/zh/redis/user-guide/master-replica-switchovers#concept-2025502)
1.2 慢查詢引起了請求堵塞
執(zhí)行時間復雜度為 O (N) 的操作,引發(fā)慢查詢和請求的堵塞,此時,客戶端發(fā)起的其他請求可能出現(xiàn)暫時性失敗。
1.3 復雜的網(wǎng)絡環(huán)境
由于客戶端與 Redis 服務器之間復雜網(wǎng)絡環(huán)境引起,可能出現(xiàn)偶發(fā)的網(wǎng)絡抖動、數(shù)據(jù)重傳等問題,此時,客戶端發(fā)起的請求可能會出現(xiàn)暫時性失敗。
2 推薦的重試準則
2.1 僅重試冪等的操作
由于超時可能發(fā)生在下述任一階段:該命令由客戶端發(fā)送成功,但尚未到達 Redis。命令到達 Redis,但執(zhí)行超時。命令在 Redis 中執(zhí)行結(jié)束,但結(jié)果返回給客戶端時發(fā)生超時。如果執(zhí)行重試可能導致某個操作在 Redis 中被重復執(zhí)行,因此不是所有操作均適合設計重試機制。通常推薦僅重試冪等的操作,例如SET操作,即多次執(zhí)行SET a b命令,那么 a 的值只可能是 b 或執(zhí)行失??;如果執(zhí)行LPUSH mylist a則不是冪等的,可能導致 mylist 中包含多個 a 元素。
2.2 適當?shù)闹卦嚧螖?shù)與間隔
根據(jù)業(yè)務需求和實際場景調(diào)整適當?shù)闹卦嚧螖?shù)與間隔,否則可能引發(fā)下述問題:如果重試次數(shù)不足或間隔太長,應用程序可能無法完成操作而導致失敗。如果重試次數(shù)過大或間隔過短,應用程序可能會占用過多的系統(tǒng)資源,且可能因請求過多而堵塞在服務器上無法恢復。常見的重試間隔方式包括立即重試、固定時間重試、指數(shù)增加時間重試、隨機時間重試等。
2.3 避免重試嵌套
避免重試嵌套,否則可能會導致重復的重試且無法停止。
2.4 記錄重試異常并打印失敗報告
在重試過程中,建議在 WARN 級別上打印重試錯誤日志,同時,僅在重試失敗時打印異常信息。
3 Jedis
建議使用 Jedis 4.0.0 及以上版本,推薦使用最新的 Jedis 版本,以下代碼為 Jedis 5.0.0 的重試示例。
3.1 添加 Jedis 的 Pom 依賴
redis.clients jedis 5.0.0
3.2 重試實戰(zhàn)
① 標準架構(gòu)實例或集群架構(gòu)代理(Proxy)模式
使用 JedisPool 模式。 該示例會將 SET 命令自動重試 5 次,且總重試時間不超過 10s,每次重試之間等待類指數(shù)間隔的時間,如果最終不成功,則拋出異常。
PooledConnectionProvider provider = new PooledConnectionProvider(HostAndPort.from("127.0.0.1:6379")); int maxAttempts = 5; // 最大重試次數(shù) 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(); }
② 集群架構(gòu)直連模式
使用 JedisCluster 模式。 可以通過配置 maxAttempts 參數(shù)來定義失敗情況下的重試次數(shù),默認值為 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(); }
4 Redisson
Redisson 客戶端提供了兩個參數(shù)來控制重試邏輯:
retryAttempts:重試次數(shù),默認為 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);
5 StackExchange.Redis
StackExchang.Redis 客戶端目前僅支持重試時連接,重試示例如下:
var conn = ConnectionMultiplexer.Connect("redis0:6380,redis1:6380,connectRetry=3");說明 如需實現(xiàn) API 級別的重試策略,請參見 Polly。
6 Lettuce
Lettuce 客戶端未提供在命令超時后重試的參數(shù),但是您可以通過下述參數(shù)來實現(xiàn)命令重試策略:
at-most-once execution:命令最多執(zhí)行 1 次,即 0 次或 1 次,如果連接斷開并重新連接,命令可能會丟失。
at-least-once execution(默認):最少成功執(zhí)行 1 次,即可能會在執(zhí)行時進行多次嘗試,保障最少成功執(zhí)行 1 次。使用此策略時,如果 Tair 實例發(fā)生了主備切換,此時客戶端可能累積了較多的重試命令,主備切換完成后可能會引發(fā) Tair 實例的 CPU 使用率激增。
說明
更多信息,請參見 Client-Options(https://github.com/lettuce-io/lettuce-core/wiki/Client-Options) 和 Command execution reliability(https://github.com/lettuce-io/lettuce-core/wiki/Command-execution-reliability)。
重試示例:
clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE;
參考:https://help.aliyun.com/zh/redis/use-cases/retry-mechanisms-for-redis-clients
通過客戶端程序連接 Redis
客戶端程序 TLS(SSL)加密連接 Redis
編輯:黃飛
-
服務器
+關注
關注
13文章
9797瀏覽量
88033 -
API
+關注
關注
2文章
1624瀏覽量
64075 -
客戶端
+關注
關注
1文章
301瀏覽量
17098 -
Redis
+關注
關注
0文章
387瀏覽量
11456
原文標題:大廠都是怎么做Redis重試的?
文章出處:【微信號:OSC開源社區(qū),微信公眾號:OSC開源社區(qū)】歡迎添加關注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
如何使用Rust連接Redis
Redis Stream應用案例
redis概述
如何使得redis中的數(shù)據(jù)不再有
設計STM32串口驅(qū)動要遵循的兩條準則是什么
圓形電路板設計事項和準則是什么?
如何在RocketMQ中合理使用重試機制
什么是 Redis

如何用Springboot整合Redis

Tenacity重試模塊實踐
Python中retrying庫的有參數(shù)重試

評論