说说你对dubbo重试机制的理解?最好能结合一下源码

1 个回答

  • 孟奇
    请优先考虑优先考虑你的人。
    Dubbo 提供了重试机制来提高调用的成功率,当一次调用失败时,可以尝试重新选择其他服务提供者并再次发起请求。重试机制主要适用于幂等性操作(如查询),以避免因重复调用造成的数据不一致。 ### 重试机制的实现原理 #### 重试配置 - **默认行为**:Dubbo 默认重试次数为 2,实际调用最多为 3 次(1 次初始调用 + 2 次重试)。 - **配置方式**: ```xml <dubbo:reference retries="3" timeout="3000" /> ``` - `retries`:配置最大重试次数。 - `timeout`:每次调用的超时时间。 #### 触发条件 - 网络异常。 - 服务端超时或不可用。 - Dubbo 内部通过负载均衡机制选择新的服务提供者发起重试。 ### 源码实现 重试逻辑的核心由 `FailoverClusterInvoker` 类实现,其 `doInvoke` 方法负责执行调用和处理重试逻辑。 #### 关键源码分析 ```java @Override public Result doInvoke(Invocation invocation, List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException { List<Invoker<T>> copyInvokers = invokers; checkInvokers(copyInvokers, invocation); int retries = getUrl().getMethodParameter(invocation.getMethodName(), RETRIES_KEY, DEFAULT_RETRIES) + 1; RpcException lastException = null; List<Invoker<T>> invoked = new ArrayList<>(copyInvokers.size()); for (int i = 0; i < retries; i++) { Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked); try { invoked.add(invoker); return invoker.invoke(invocation); } catch (RpcException e) { lastException = e; if (e.isBiz()) { throw e; // 业务异常直接抛出 } } } throw new RpcException("Failed after retries: " + retries, lastException); } ``` #### 逻辑解析 1. **获取重试次数**: 使用 `getUrl` 获取 `retries` 参数,默认为 2。 2. **选择服务提供者**: 调用 `select` 方法,通过负载均衡算法选择合适的服务提供者,确保重试时尽量选择不同的实例。 3. **调用服务**: 调用目标服务的 `invoke` 方法,如果成功返回结果。 4. **异常处理**: - 网络异常或超时捕获后进行下一次重试。 - 如果发生业务异常(如方法逻辑错误),直接抛出,不再重试。 5. **重试结束**: 达到最大重试次数仍未成功时,抛出最后一次捕获的异常。 ### 优势与使用注意 #### 优势 1. **提高成功率**:在服务端部分不可用的情况下,通过重试机制可以增加调用成功的可能性。 2. **结合负载均衡**:每次重试选择不同的服务实例,避免因单点故障影响系统可用性。 #### 注意事项 1. **非幂等操作的风险**: 非幂等性操作(如扣款、订单生成)不适合开启重试,可能导致数据不一致。 2. **性能开销**: 重试会增加服务端负担,在服务端压力较大时需谨慎配置。 3. **配置合理性**: 根据业务需求设置合适的重试次数和超时时间,避免因过多重试导致响应延迟。 ### 总结 Dubbo 的重试机制通过 `FailoverClusterInvoker` 类实现,基于负载均衡策略在调用失败时选择不同的服务提供者进行重试。它在提升服务可用性和容错能力方面具有重要作用,但需合理配置重试参数并谨慎使用在非幂等性场景中,以确保系统的稳定性和一致性。
    发布于 2024-12-11 12:22 •IP属地 安徽
    举报
    评论
    收藏