受网络和运行环境影响 , 应用程序可能遇到暂时性故障,如瞬时网络抖动、服务暂时不可用、服务繁忙导致超时等 。
自动重试机制可大幅避免此类故障,保障操作成功执行 。
1 引发暂时性故障的原因1.1 故障触发了高可用机制
云 redis 支持节点健康状态监测,当监测到实例中的主节点不可用时,会自动触发主备切换,例如将主节点和从节点进行互换,保障实例的高可用性 。此时,客户端可能会遇到下列暂时性故障:秒级的连接闪断 。30 秒内的只读状态(用于避免主备切换引起潜在的数据丢失风险和双写) 。
更多参见:主备切换(https://help.aliyun.com/zh/redis/user-guide/master-replica-switchovers#concept-2025502)
1.2 慢查询引起了请求堵塞
执行时间复杂度为 O (N) 的操作 , 引发慢查询和请求的堵塞,此时,客户端发起的其他请求可能出现暂时性失败 。
1.3 复杂的网络环境
由于客户端与 Redis 服务器之间复杂网络环境引起,可能出现偶发的网络抖动、数据重传等问题,此时,客户端发起的请求可能会出现暂时性失败 。
2 推荐的重试准则2.1 仅重试幂等的操作
由于超时可能发生在下述任一阶段:该命令由客户端发送成功 , 但尚未到达 Redis 。命令到达 Redis,但执行超时 。命令在 Redis 中执行结束,但结果返回给客户端时发生超时 。如果执行重试可能导致某个操作在 Redis 中被重复执行,因此不是所有操作均适合设计重试机制 。通常推荐仅重试幂等的操作,例如 SET操作 , 即多次执行 SET a b命令,那么 a 的值只可能是 b 或执行失败;如果执行 LPUSH mylist a则不是幂等的 , 可能导致 mylist 中包含多个 a 元素 。
2.2 适当的重试次数与间隔
根据业务需求和实际场景调整适当的重试次数与间隔,否则可能引发下述问题:如果重试次数不足或间隔太长,应用程序可能无法完成操作而导致失败 。如果重试次数过大或间隔过短,应用程序可能会占用过多的系统资源,且可能因请求过多而堵塞在服务器上无法恢复 。常见的重试间隔方式包括立即重试、固定时间重试、指数增加时间重试、随机时间重试等 。
2.3 避免重试嵌套
避免重试嵌套 , 否则可能会导致重复的重试且无法停止 。
2.4 记录重试异常并打印失败报告
在重试过程中,建议在 WARN 级别上打印重试错误日志,同时,仅在重试失败时打印异常信息 。
3 Jedis
建议使用 Jedis 4.0.0 及以上版本,推荐使用最新的 Jedis 版本,以下代码为 Jedis 5.0.0 的重试示例 。
3.1 添加 Jedis 的 Pom 依赖<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.0.0</version>
</dependency>
3.2 重试实战① 标准架构实例或集群架构代理(Proxy)模式
使用 JedisPool 模式 。
该示例会将 SET 命令自动重试 5 次,且总重试时间不超过 10s , 每次重试之间等待类指数间隔的时间,如果最终不成功,则抛出异常 。
PooledConnectionProvider provider = newPooledConnectionProvider(HostAndPort.from("127.0.0.1:6379"));
intmaxAttempts = 5; // 最大重试次数
Duration maxTotalRetriesDuration = Duration.ofSeconds(10); // 最大的重试时间
UnifiedJedis jedis = newUnifiedJedis(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");
intconnectionTimeout = 5000;
intsoTimeout = 2000;
intmaxAttempts = 5;
ConnectionPoolConfig config = newConnectionPoolConfig;
JedisCluster jedisCluster = newJedisCluster(hostAndPort, connectionTimeout, soTimeout, maxAttempts, config);
try{
System.out.println("set key: "+ jedisCluster.set("key", "value"));
} catch(Exception e) {
// 表示尝试maxAttempts之后仍旧没有访问成功 。
e.printStackTrace;
}
4 Redisson
Redisson 客户端提供了两个参数来控制重试逻辑:
推荐阅读
- 如何制作连环衣钩 连环鱼钩怎么绑?
- 微波炉不转了怎么回事 微波炉转盘不转了怎么回事
- 抖店商品卡怎么推广?怎么带来流量?
- 微波炉突然不加热啦是怎么回事 微波炉运转正常不加热的解决办法
- pps怎么下载电影 pps下载的视频是什么格式
- xbox无法登录怎么办 xbox登录不了问题解决方法
- steam怎么换区 steam两种转区方法介绍
- steamdeck游戏下载慢怎么办 steamdeck下载失败问题解决方法
- switch联网连不上怎么解决?switch联网问题这样解决
- 兔子味道大,想养一只兔子我应该喂它吃什么才没那么大的异味笼养好还是散养好会不会乱跑会经常生病我应该怎么做