Spring Retry 重试机制


前言:

    在微服务领域, 一种通信方法是synchronous(同步)。事实是我们无法避免网络故障,临时服务停机(由于重启或崩溃)。当客户端需要实时数据且下游服务暂时没有响应时,它可能会影响用户体验,因此应该创建重试机制,Java中提供了许多解决方案选项。

  • 重试可能会导致资源堵塞从而阻止应用程序恢复; 因此,重试次数必须有限如3,不超过5次左右。

  • 不应对每个例外进行重试。它应该仅针对特定类型的异常进行编码。例如,不要在Exception.class周围放置代码,而是为SQLException.class执行此操作。

  • 重试可能导致多个线程尝试访问相同的共享资源,锁可能是一个大问题。必须应用指数退避算法来持续增加重试之间的延迟,直到达到最大限制。

  • 在应用重试时,必须处理幂等性。再次触发相同的请求不应该触发系统中的重复事务。

  现在构建一个简单的服务,展示Spring Retry如何帮助解决Retry问题。

#基于springBoot2.x
Gradle 

dependencies {
 implementation('org.springframework.boot:spring-boot-starter-web')
 implementation('org.springframework.retry:spring-retry')
 implementation('org.springframework.boot:spring-boot-starter-aop')
 testImplementation('org.springframework.boot:spring-boot-starter-test')
}

#Spring Retry在内部使用Spring AOP来工作,因此必须将其添加为依赖项。

1. @EnableRetry (启动类)

@EnableRetry
@SpringBootApplication
public class Application {
 public static void main(String[] args) {
  SpringApplication.run(DemoApplication.class, args);
 }
}

2.重试逻辑放入服务

   @Retryable注释必须应用于需要具有重试逻辑的方法。 以下段代码中,放了一个计数器变量,在日志中显示尝试重试逻辑的次数。

  • 您可以配置应触发重试的异常。

  • 它还可以定义它可以执行的重试次数。如果不定义,则默认值为3。 

  • 一旦所有重试尝试都用完,服务仍会抛出异常(SQLException)将调用@Recover方法。recover方法应该处理这些请求的回退机制

@Service
public class BillingService {
    private static final Logger LOGGER = LoggerFactory.getLogger(BillingService.class);

    int counter =0;

    @Retryable(value = { SQLException.class }, maxAttempts = 3)
    public String simpleRetry() throws SQLException {
        counter++;
        LOGGER.info("Billing Service Failed "+ counter);
        throw new SQLException();
    }

    @Recover
    public String recover(SQLException t){
        LOGGER.info("Service recovering");
        return "Service recovered from billing service failure.";
    }

}

启动测试:

@RestController
@RequestMapping(value="/billing")
public class BillingClientService {

    @Autowired
    private BillingService billingService;

    @GetMapping
    public String callRetryService() throws SQLException {
        return billingService.simpleRetry();
    }
}

#http://localhost:8080/billing
2019-03-16 10:59:51.399  INFO 17288 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 1
2019-03-16 10:59:52.401  INFO 17288 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 2
2019-03-16 10:59:53.401  INFO 17288 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 3
2019-03-16 10:59:53.402  INFO 17288 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Service recovering

日志显示它已经尝试了3次simpleRetry方法,然后路由到recover方法。

3.BackOff策略在重试之间创建延迟

//每次重试时间隔5秒 
@Retryable(value = { SQLException.class }, maxAttempts = 3, backoff = @Backoff(delay = 5000))
    public String simpleRetry() throws SQLException {
        counter++;
        LOGGER.info("Billing Service Failed "+ counter);
        throw new SQLException();
    }
#http://localhost:8080/billing
2019-03-17 23:02:12.491  INFO 53392 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 1
2019-03-17 23:02:17.494  INFO 53392 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 2
2019-03-17 23:02:22.497  INFO 53392 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Billing Service Failed 3
2019-03-17 23:02:22.497  INFO 53392 --- [nio-8080-exec-1] c.e.springretrydemo.BillingService: Service recovering

在Java中应用Retry模式还有许多其他选项:

  • Failsafe  是一个用于处理故障的轻量级零依赖库。具有用于处理日常用例的简洁API以及处理其他所有内容的灵活性。 

  • Java 8功能接口

 


 

你可能感兴趣的:(java,微服务,架构)