SpringCloud重試retry是一個很贊的功能,能夠有效的處理單點故障的問題。主要功能是當請求一個服務的某個執行個體時,譬如你的User服務啟動了2個,它們都在eureka裡注冊了,那麼正常情況下當請求User服務時,ribbon預設會輪詢這兩個執行個體。此時如果其中一個執行個體故障了,發生了當機或者逾時等,如果沒有配置啟用重試retry政策,那麼調用方就會得到錯誤資訊或者逾時無響應或者是熔斷傳回的資訊。我們希望的自然是一個故障了,會自動切換到另一個去通路。
最簡單的方法就是retry。
需要先在pom.xml裡加入
- <dependency>
- <groupId>org.springframework.retry</groupId>
- <artifactId>spring-retry</artifactId>
- </dependency>
ribbon、zuul、feign都可以配置各自的retry方式。
1 ribbon配置如下
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5yNzQDM5QDOzQDNlBTMyczMzYzX2AjMwEDMxAzLcBTMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
- @Bean
- @LoadBalanced
- RestTemplate restTemplate() {
- HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
- httpRequestFactory.setReadTimeout(5000);
- httpRequestFactory.setConnectTimeout(5000);
- return new RestTemplate(httpRequestFactory);
- }
2 zuul配置如下
zuul的重試比較簡單,不需要任何代碼,直接在yml裡配置即可。
注意,配置時,ribbon開頭的在yml裡是不給提示的,不要以為不提示就是沒效果,其實是可以用的。
這個ReadTimeout和ConnectTimeout差別是很大的,ConnectTimeout是指建立連接配接的時間,如果目标服務當機或網絡故障,那麼響應的就是ConnectTimeout,無法連接配接。而ReadTimeout則是連接配接建立後,等待目标服務傳回響應的時間,譬如目标服務做了一個複雜操作導緻耗時較長,那麼會觸發ReadTimeout。
譬如zuul路由了/user路徑到user服務上,如果User1執行個體當機了,那麼配置了retry的zuul就會在重試MaxAutoRetries次數後,切換到另一個執行個體User2上。如果User2也故障了,那麼傳回404.
retryableStatusCodes裡面有幾個錯誤碼,意思就是遇到哪些錯誤碼時觸發重試。預設是404,我多配了幾個,僅供參考。
3 feign配置如下
feign預設是通過自己包下的Retryer進行重試配置,預設是5次
- import static java.util.concurrent.TimeUnit.SECONDS;
- /**
- * Cloned for each invocation to {@link Client#execute(Request, feign.Request.Options)}.
- * Implementations may keep state to determine if retry operations should continue or not.
- */
- public interface Retryer extends Cloneable {
- /**
- * if retry is permitted, return (possibly after sleeping). Otherwise propagate the exception.
- */
- void continueOrPropagate(RetryableException e);
- Retryer clone();
- public static class Default implements Retryer {
- private final int maxAttempts;
- private final long period;
- private final long maxPeriod;
- int attempt;
- long sleptForMillis;
- public Default() {
- this(100, SECONDS.toMillis(1), 5);
- }
- public Default(long period, long maxPeriod, int maxAttempts) {
- this.period = period;
- this.maxPeriod = maxPeriod;
- this.maxAttempts = maxAttempts;
- this.attempt = 1;
- }
- @Bean
- Retryer feignRetryer() {
- return Retryer.NEVER_RETRY;
- }
- @Bean
- Request.Options requestOptions(ConfigurableEnvironment env){
- int ribbonReadTimeout = env.getProperty("ribbon.ReadTimeout", int.class, 6000);
- int ribbonConnectionTimeout = env.getProperty("ribbon.ConnectTimeout", int.class, 3000);
- return new Request.Options(ribbonConnectionTimeout, ribbonReadTimeout);
- }