RPC如何实现超时重试

  • Post author:
  • Post category:其他



目录


代码


UUID


为什么要重试


我们发起一次 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可能相同,不会存在不同时间内生成重复的数据.



版权声明:本文为weixin_40757930原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。