重试的场景
重试的定义:我们认为这个故障是暂时的,而不是永久的,所以我们会去重试。
要重试:调用超时,被调用端返回了某种可以重试的错误(如繁忙中,流程中,维护中,资源不足等)
不要重试:业务级别的错误(如没有权限,或者是非法数据等),技术上的错误(如http的500等),这类型的错误重试下去没有意义。
重试的策略:
总原则:有个重试次数的最大值,经过一段时间不断的重试之后,就没有必要再重试了,应该报故障了,这样可以避免因为重试过多而导致网络上的负担更重
- No BackOff 无退避算法策略,即当重试时是立即重试
Fixed BackOff 固定时间的退避策略,需设置参数
1
23. UniformRandom BackOff 随机时间退避策略,需设置```sleeper```、```minBackOffPeriod```和```maxBackOffPeriod```。该策略在[```minBackOffPeriod```,```maxBackOffPeriod```]之间取一个随机休眠时间,```minBackOffPeriod```默认为500毫秒,```maxBackOffPeriod```默认为1500毫秒
4. Exponential Backoff 指数级退避策略,每一次重试所需要的休息时间都会翻倍增加。让被调用方能够有更多的时间来从容处理我们的请求,和TCP的拥塞机制有点像。需设置参数```sleeper```、```initialInterval```、```maxInterval```和```multiplier```。```initialInterval```指定初始休眠时间,默认为100毫秒。```maxInterval```指定最大休眠时间,默认为30秒。```multiplier```指定乘数,即下一次休眠时间为当前休眠时间 * ```multiplierExponentialRandom BackOff 随机指数退避策略,引入随机乘数,固定乘数可能会引起很多服务同时重试导致DDos,使用随机休眠时间来避免这种情况。
example:
指数级退避策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37//最大延迟时间间隔,单位是毫秒
private static int MAX_WAIT_INTERVAL = 100*1000;
//最大重试次数
private static int MAX_RETRIES = 3;
//指数退避算法
public static void doOperationAndWaitForResult(){
try{
int retries = 0;
boolean retry = false;
do {
long waitTime = Math.min(getWaitTimeExp(retries), MAX_WAIT_INTERVAL);
System.out.print("等待时间:" + waitTime + " ms \n");
//Wait for the result
Thread.sleep(waitTime);
//Get the result of the asynchronous operation
Results results = getAsyncOperationResult();
if (Results.SUCCESS == results){
retry = false;
}else if (Results.NOT_READY == results || Results.THROTTLED == results
|| Results.SERVER_ERROR == results){
retry = true;
}else {
retry = false;
}
}while (retry && (retries ++ < MAX_RETRIES));
}catch (Exception e){
}
}
/**
* 根据重试的次数,返回2的指数的等待时间
* @param retryCount
* @return
*/
public static long getWaitTimeExp(int retryCount){
long waitTime = ((long) Math.pow(2, retryCount) * 100L);
return waitTime;
}随机时间退避策略:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22private void avoidTime(int retryTime) {
int tryTime = RETRY_TIME - retryTime;
Random random = new Random(System.currentTimeMillis());
int time = 0;
switch (tryTime) {
case 1:
case 2:
time = random.nextInt(150) + 50;
break;
case 3:
time = random.nextInt(300) + 200;
break;
default:
time = random.nextInt(150);
break;
}
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}