0 来张图
1 首先定义远程服务提供的服务
1.1 定义接口
/** * Created by haoran_10 on 2017/8/6. * 远程服务 */public interface RpcService { /** * 执行服务 * @param inParam * @return */ public Resultexecute(ContextDTO contextDTO); /** * 取消服务 * @param contextDTO * @return */ public Result cancel(ContextDTO contextDTO);}
1.2 返回结果
- 成功结果
- 业务类型错误结果
- 不可预知系统错误结果
1.3 远程服务要求
- 执行服务&取消服务 都要求幂等性
2.调用远程服务
public boolean doDistributedTransaction(ContextDTO contextDTO){ try{ //1.执行本地服务 callLocalService(contextDTO); //2.执行远程服务A try{ //2.1 调用远程服务 Result rpcA = rpcServiceA.execute(contextDTO); //2.1.1 业务结果错误,直接返回 if(rpcA.businessError()){ log.error("call rpc execute business error,rpcA:{}",rpcA); //抛出回滚 throw RollbackException(contextDTO); } //2.1.2 系统结果错误,加入重试任务 if(rpcA.systemError()){ log.error("call rpc execute system error,rpcA:{}",rpcA); saveRetryTask(contextDTO); } //2.1.3 调用成功,继续下面的远程调用 if(rpcA.success()){ } }catch(Exception rpcAException){ //2.1.4 捕获异常,执行重试 log.error("call rpc execute is error,{}",rpcAException); saveRetryTask(contextDTO); } //3. 执行远程服务B Result rpcB = rpcServiceB.confirm(contextDTO); //.... //n. 执行远方服务N //... }catch(Exception e){ //记录错误日志 log.error("doDistributedTransaction is error,contextDTO:{};e:{}",contextDTO,e); //如果回滚异常,回滚服务 if(e instanceof RollbackException){ rollBack(contextDTO); }else{ saveRetryTask(contextDTO); } }}
- 要求请求远程服务时,由调用方生成唯一key,确保业务唯一性
3.回滚服务
public boolean rollBack(ContextDTO contextDTO){ rpcServiceA.cancel(contextDTO); rpcServiceB.cancel(contextDTO); rpcServiceN.cancel(contextDTO);}
- 这里要求取消必定成功,如果不成功,可以加入重试任务服务重试回滚
4.重试服务
//异步式执行重试任务public void retryTaskCenter(){ int defineRetryTimes = 3;//定义重试次数 while(true){ //查询出需要重试任务的数据 Listlist = queryRetryTask(queryParam); for(RetryTask retryTask:list){ ContextDTO contextDTO = buildContextDTOFromRetryTask(retryTask); int retryTimes = 0; while(retryTimes
5.使用场景
- 调用链路较短
- 要求分布式强一致性
如果时调用链路非常长,则非常推荐使用一致性消息机制