目录
为什么要重试
我们发起一次 RPC 调用,去调用远程的一个服务,但是
网络突然抖了一下,导致我们的请求失败了,而这个请求我们希望它能够尽可能地执行成
功,那这时我们要怎么做呢?
我们需要重新发起一次 RPC 调用,那我们在代码中该如何处理呢?是在代码逻辑里 catch
一下,失败了就再发起一次调用吗?这样做显然不够优雅吧。
这时我们就可以考虑使用
RPC 框架的重试机制。
当然也不是所有的操作都要重试,所以这个也要作为参数去配置。
在使用 RPC 框架的时候,我们要确保
被调用的服务的业务逻辑是幂等
的,这样我们才能考虑根据事件情况开启 RPC 框架的异常重试功能。
代码
当
当前时间在超时范围内
或者
是已经超时 但是还有超时次数
,
就去结果集中拿取结果判断,如果有结果则返回,没有则判断是否超时,如果超时进入 超时重试阶段。
超时重试的时候 客户端会重新进行路由,所以这次的请求会发给和上次不同的服务端。
这里采用的是立即重试,dubbo也是这种机制,还有其他的重试机制。
RocketMQ是间隔性重试,它对于请求的结果没有实时性的要求,例如典型的消息消费场景。
java 重试机制总结_猴子哥哥1024的博客-CSDN博客_java 重试三次
// 当 当前时间已经在 超时范围内 就去结果集中拿取结果判断
// 或者是已经超时 但是超时次数还有 则进入 超时重试阶段
while (System.currentTimeMillis() - beginTime < timeOut || rpcInvocation.getRetry() > 0) {
// RpcInvocation 是请求 里面有请求参数 全类名 等等信息
Object object = RESP_MAP.get(rpcInvocation.getUuid());
if (object instanceof RpcInvocation) {
// 只要是RpcInvocation 说明该请求已经被调用并且得到返回结果了 返回结果即可
RpcInvocation rpcInvocationResp = (RpcInvocation) object;
RESP_MAP.remove(rpcInvocation.getUuid());
return rpcInvocationResp.getResponse();
}else if(rpcInvocation.getRetry() > 0){
// 如果设置了超时重试 那么判断时间 是否需要重试,
// 如果时间在 timeOut范围内 那么不需要
if (System.currentTimeMillis() - beginTime > timeOut) {
System.out.println(" 超时重试 ");
retryTimes++;
//重新请求
rpcInvocation.setRetry(rpcInvocation.getRetry() - 1);// 超时次数减一
SEND_QUEUE.add(rpcInvocation);// 把该请求重新发送
beginTime = System.currentTimeMillis(); // 重置计时时刻
}
}
}
RESP_MAP.remove(rpcInvocation.getUuid());
throw new TimeoutException("Wait for response from server on client " + timeOut + " ms,retry times is " + retryTimes + ",service's name is " + rpcInvocation.getTargetServiceName() + "#" + rpcInvocation.getTargetMethod());
需要注意的是 uuid 的生成,因为在一台机器上可能会并发的发送请求,那么此时uuid可能会重复,所以在代理类中,需要这样设置
private static final Object lock = new Object(); // 类变量
// 在生成uuid 时加锁
synchronized (lock){
rpcInvocation.setUuid(UUID.randomUUID().toString());
}
UUID
UUID是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的
UUID由以下几部分的组合:
(1)当前日期和时间,UUID的第一个部分与时间有关,如果你在生成一个UUID之后,过几秒又生成一个UUID,则第一个部分不同,其余相同。
(2)时钟序列。
(3)全局唯一的IEEE机器识别号,如果有网卡,从网卡MAC地址获得,没有网卡以其他方式获得。
通过组成可以看出,首先每台机器的mac地址是不一样的,那么如果出现重复,可能是同一时间下生成的id可能相同,不会存在不同时间内生成重复的数据.