wordpress建手机站教程,新网站建设渠道,排名点击软件怎样,怎样建一个自己公司的网站目录
一、核心概念#xff1a;重试的适用场景
二、方案 1#xff1a;OpenFeign 原生重试#xff08;基于 Retryer#xff09;
1. 原生 Retryer 接口定义
2. 内置重试实现#xff1a;Default
3. 配置原生重试#xff08;两种方式#xff09;
方式 1#xff1a;配置…目录一、核心概念重试的适用场景二、方案 1OpenFeign 原生重试基于 Retryer1. 原生 Retryer 接口定义2. 内置重试实现Default3. 配置原生重试两种方式方式 1配置文件全局生效方式 2自定义 Retryer Bean推荐更灵活4. 原生重试的核心规则5. 自定义 Retryer完全控制重试逻辑三、方案 2集成 Spring Retry更灵活1. 核心依赖2. 启用 Spring Retry3. 配置重试策略三种方式方式 1注解方式推荐细粒度控制方式 2全局配置重试模板方式 3编程式调用手动控制重试4. Spring Retry 核心注解说明四、方案 3结合熔断组件Sentinel/Hystrix1. 集成 Sentinel 示例2. 核心规则五、关键扩展自定义重试触发条件六、生产环境最佳实践1. 重试配置建议2. 核心注意事项3. 禁用重试的场景七、问题排查1. 重试不生效2. 重试次数超出预期3. 重试导致重复数据总结OpenFeign 本身内置了重试机制基于feign.Retryer接口同时也可结合 Spring Retry 实现更灵活的重试策略如按异常类型、返回值重试。本文从原生重试、Spring Retry 集成、高级定制三个维度全面讲解 Feign 请求重试的实现方式、配置细节和最佳实践。一、核心概念重试的适用场景重试仅适用于幂等性请求如 GET 查询、PUT 更新严禁对非幂等请求如 POST 创建重试否则可能导致重复创建数据、重复扣款等严重问题。✅ 推荐重试网络抖动、超时、5xx 服务端错误如 500/502/503/504❌ 禁止重试4xx 客户端错误如 400 参数错误、401 未授权、403 禁止访问、404 资源不存在。二、方案 1OpenFeign 原生重试基于 RetryerFeign 内置了Retryer接口通过实现该接口可自定义重试逻辑是轻量、无依赖的重试方案。1. 原生 Retryer 接口定义java运行public interface Retryer extends Cloneable { // 执行重试若允许重试则等待后返回否则抛出RetryableException void continueOrPropagate(RetryableException e); // 克隆重试器Feign 每次请求会创建新的重试器实例 Retryer clone(); // 内置默认实现默认不重试NEVER_RETRY Retryer NEVER_RETRY new Retryer() { Override public void continueOrPropagate(RetryableException e) { throw e; // 直接抛出异常不重试 } Override public Retryer clone() { return this; } }; }2. 内置重试实现DefaultFeign 提供了Retryer.Default实现支持配置最大重试次数、初始间隔、最大间隔java运行// 构造函数参数说明 public Default(long period, long maxPeriod, int maxAttempts) { this.period period; // 初始重试间隔毫秒 this.maxPeriod maxPeriod; // 最大重试间隔毫秒 this.maxAttempts maxAttempts; // 最大重试次数含首次请求 this.attempt 1; }3. 配置原生重试两种方式方式 1配置文件全局生效yaml# application.yml feign: client: config: default: # 所有Feign客户端生效替换为服务名可指定客户端 retryer: # 最大重试次数含首次请求如3首次2次重试 maxAttempts: 3 # 初始重试间隔毫秒 period: 1000 # 最大重试间隔毫秒 maxPeriod: 3000方式 2自定义 Retryer Bean推荐更灵活java运行import feign.Retryer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; Configuration public class FeignRetryConfig { /** * 自定义原生重试器 * 说明maxAttempts3首次请求2次重试初始间隔1秒最大间隔3秒 */ Bean public Retryer feignRetryer() { // Default重试器会采用指数退避策略间隔时间 min(period * 2^(attempt-1), maxPeriod) // 例如第1次重试间隔1秒第2次重试间隔2秒1*2^1达到maxPeriod后不再增加 return new Retryer.Default(1000, 3000, 3); } }4. 原生重试的核心规则Feign 原生重试仅对RetryableException异常触发如连接超时、读取超时、5xx 错误4xx 错误默认不会触发重试Feign 会抛出非重试型异常重试间隔采用指数退避策略避免短时间内重复请求压垮服务若需自定义重试触发条件如特定 4xx 错误也重试需扩展ErrorDecoder。5. 自定义 Retryer完全控制重试逻辑java运行import feign.RetryableException; import feign.Retryer; import org.springframework.stereotype.Component; Component public class CustomRetryer implements Retryer { // 最大重试次数含首次 private static final int MAX_ATTEMPTS 3; // 重试间隔固定1秒不使用指数退避 private static final long PERIOD 1000; // 当前重试次数 private int attempt 1; Override public void continueOrPropagate(RetryableException e) { // 超过最大次数则抛出异常终止重试 if (attempt MAX_ATTEMPTS) { throw e; } // 记录重试日志 System.out.printf(Feign请求重试第%d次异常%s%n, attempt, e.getMessage()); // 等待重试间隔 try { Thread.sleep(PERIOD); } catch (InterruptedException ignored) { Thread.currentThread().interrupt(); } // 重试次数1 attempt; } Override public Retryer clone() { // 每次请求创建新的重试器实例重置attempt return new CustomRetryer(); } }三、方案 2集成 Spring Retry更灵活原生重试仅支持基于异常的重试而 Spring Retry 可实现按异常类型、返回值、自定义条件重试支持重试监听、退避策略等高级特性是生产环境的首选方案。1. 核心依赖xml!-- Spring Retry 核心依赖 -- dependency groupIdorg.springframework.retry/groupId artifactIdspring-retry/artifactId version1.3.4/version /dependency !-- 需引入AOP依赖Spring Retry 基于AOP实现 -- dependency groupIdorg.springframework/groupId artifactIdspring-aspects/artifactId /dependency2. 启用 Spring Retry在启动类添加EnableRetry注解java运行import org.springframework.retry.annotation.EnableRetry; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; SpringBootApplication EnableRetry // 启用Spring Retry public class FeignDemoApplication { public static void main(String[] args) { SpringApplication.run(FeignDemoApplication.class, args); } }3. 配置重试策略三种方式方式 1注解方式推荐细粒度控制在 Feign 接口方法上添加Retryable注解指定重试规则java运行import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.retry.annotation.Recover; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; FeignClient(name user-service) public interface UserFeignClient { /** * 重试规则 * - 仅对指定异常超时、5xx重试 * - 最大重试次数2次首次2次共3次 * - 重试间隔初始1秒指数退避第2次重试2秒 */ Retryable( // 触发重试的异常类型 include { feign.RetryableException.class, // Feign原生重试异常 java.net.SocketTimeoutException.class, // 超时异常 org.springframework.web.client.HttpServerErrorException.class // 5xx服务端错误 }, // 排除不重试的异常 exclude { org.springframework.web.client.HttpClientErrorException.class // 4xx客户端错误 }, // 最大重试次数不含首次即maxAttempts2 → 首次2次重试 maxAttempts 2, // 退避策略initialInterval初始间隔multiplier指数倍数 backoff Backoff(initialInterval 1000, multiplier 2) ) GetMapping(/user/{id}) UserDTO getUserById(PathVariable(id) Long id); /** * 重试耗尽后的降级方法必须与重试方法同参数、同返回值 */ Recover default UserDTO recover(Exception e, Long id) { // 降级逻辑返回默认值/空值/抛自定义异常 System.out.printf(获取用户失败id%d异常%s%n, id, e.getMessage()); return new UserDTO(); } }方式 2全局配置重试模板java运行import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.retry.backoff.ExponentialBackOffPolicy; import org.springframework.retry.policy.SimpleRetryPolicy; import org.springframework.retry.support.RetryTemplate; Configuration public class RetryConfig { /** * 全局重试模板 */ Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate new RetryTemplate(); // 1. 重试策略最大重试2次仅对指定异常重试 SimpleRetryPolicy retryPolicy new SimpleRetryPolicy(); retryPolicy.setMaxAttempts(2); // 重试次数不含首次 // 指定可重试的异常 retryPolicy.setRetryableExceptions( feign.RetryableException.class, java.net.SocketTimeoutException.class ); // 指定不可重试的异常 retryPolicy.setFatalExceptions( org.springframework.web.client.HttpClientErrorException.class ); retryTemplate.setRetryPolicy(retryPolicy); // 2. 退避策略指数退避初始1秒最大3秒 ExponentialBackOffPolicy backOffPolicy new ExponentialBackOffPolicy(); backOffPolicy.setInitialInterval(1000); // 初始间隔 backOffPolicy.setMaxInterval(3000); // 最大间隔 backOffPolicy.setMultiplier(2); // 指数倍数 retryTemplate.setBackOffPolicy(backOffPolicy); return retryTemplate; } }方式 3编程式调用手动控制重试java运行import org.springframework.retry.support.RetryTemplate; import org.springframework.stereotype.Service; import javax.annotation.Resource; Service public class UserService { Resource private UserFeignClient userFeignClient; Resource private RetryTemplate retryTemplate; public UserDTO getUser(Long id) { // 编程式重试 return retryTemplate.execute( // 重试逻辑 context - userFeignClient.getUserById(id), // 降级逻辑 context - { System.out.printf(重试耗尽id%d%n, id); return new UserDTO(); } ); } }4. Spring Retry 核心注解说明注解核心参数作用Retryableinclude指定触发重试的异常类型数组exclude指定不触发重试的异常类型数组maxAttempts最大重试次数不含首次请求默认 3backoff退避策略Backoff 注解BackoffinitialInterval初始重试间隔毫秒默认 1000multiplier指数退避倍数默认 1即固定间隔maxInterval最大重试间隔毫秒默认 0无限制Recover无重试耗尽后的降级方法参数需包含重试方法的参数 异常类型四、方案 3结合熔断组件Sentinel/Hystrix生产环境中重试通常与熔断配合使用避免重试导致服务雪崩流程为重试 → 重试耗尽 → 熔断降级。1. 集成 Sentinel 示例java运行import com.alibaba.csp.sentinel.annotation.SentinelResource; import org.springframework.retry.annotation.Retryable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; FeignClient(name user-service) public interface UserFeignClient { Retryable( include {feign.RetryableException.class}, maxAttempts 2, backoff Backoff(initialInterval 1000) ) SentinelResource( value getUserById, fallback fallbackGetUser // 熔断降级方法 ) GetMapping(/user/{id}) UserDTO getUserById(PathVariable(id) Long id); // 熔断降级方法与原方法参数一致 default UserDTO fallbackGetUser(Long id) { return new UserDTO(); } }2. 核心规则重试次数不宜过多建议 1-2 次否则会增加服务响应时间甚至导致雪崩熔断阈值需包含重试次数如熔断规则10 秒内 5 次失败则熔断避免重试次数被计入失败次数导致熔断提前触发。五、关键扩展自定义重试触发条件Feign 原生仅对RetryableException重试若需对特定 HTTP 状态码如 408 请求超时、503 服务不可用触发重试需自定义ErrorDecoderjava运行import feign.Response; import feign.RetryableException; import feign.codec.ErrorDecoder; import org.springframework.stereotype.Component; Component public class CustomErrorDecoder implements ErrorDecoder { private final ErrorDecoder defaultErrorDecoder new Default(); Override public Exception decode(String methodKey, Response response) { Exception exception defaultErrorDecoder.decode(methodKey, response); // 对特定状态码触发重试 int status response.status(); if (status 408 || status 500) { // 抛出RetryableException触发重试 return new RetryableException( response.status(), exception.getMessage(), response.request().httpMethod(), (Throwable) exception, null, response.request() ); } // 其他状态码返回原异常不重试 return exception; } }六、生产环境最佳实践1. 重试配置建议配置项推荐值说明最大重试次数1-2 次含首次过多重试会增加响应时间建议仅重试 1-2 次重试间隔1-3 秒指数退避避免短时间重复请求给服务恢复时间重试触发条件仅 5xx / 超时 / 网络异常4xx 客户端错误不重试避免无效重试日志记录开启重试日志记录每次重试的原因、次数、间隔便于问题排查2. 核心注意事项❌ 禁止对 POST 请求重试POST 通常是非幂等的重试可能导致重复创建数据✅ 幂等性保障若必须对写请求重试需通过幂等性设计如唯一请求 ID、乐观锁避免重复操作⚠️ 超时时间Feign 超时时间需包含重试总耗时如单次超时 3 秒2 次重试 → 总超时 ≥ 9 秒 监控告警对重试次数过多的接口告警排查服务稳定性问题 粒度控制不同 Feign 客户端配置不同的重试策略核心服务重试次数少非核心服务可适当增加。3. 禁用重试的场景非幂等请求POST 创建、DELETE 删除实时性要求高的接口如秒杀、实时查询下游服务明确禁止重试如返回Retry-After头接口响应慢但成功率高重试会增加整体响应时间。七、问题排查1. 重试不生效检查是否抛出RetryableException可通过自定义ErrorDecoder确保Spring Retry 需引入spring-retry和spring-aspects依赖且启动类添加EnableRetry检查Retryable注解的include是否包含目标异常类型。2. 重试次数超出预期区分「原生 Retryer」和「Spring Retry」两者不要同时使用避免重复重试检查maxAttempts定义原生 Retryer 是「含首次」Spring Retry 是「不含首次」。3. 重试导致重复数据立即停止重试检查请求是否为非幂等POST为写请求添加幂等性控制如请求 ID 去重。总结OpenFeign 实现重试有两种核心方案原生 Retryer轻量、无依赖适合简单场景仅支持基于RetryableException的重试Spring Retry功能丰富支持按异常类型、返回值重试支持退避策略、降级方法是生产环境首选。核心原则仅对幂等请求重试控制重试次数和间隔结合熔断避免雪崩做好日志和监控。