Spring Boot分布式项目异常处理实战:从崩溃边缘到优雅恢复
当单体应用拆分成分布式系统,异常就像被打开的潘多拉魔盒:RPC调用超时、分布式事务雪崩、第三方接口突然罢工…在最近的电商大促中,我们的系统就经历了这样的至暗时刻。本文将用真实代码示例,展示如何构建分布式异常处理体系。
一、全局异常拦截:最后的防线
@RestControllerAdvice
public class GlobalExceptionHandler {
// 处理业务异常
@ExceptionHandler(BizException.class)
public Result handleBizException(BizException e) {
log.error("业务异常: {}", e.getErrorMsg());
return Result.fail(e.getErrorCode(), e.getErrorMsg());
}
// 处理Feign调用异常
@ExceptionHandler(FeignException.class)
public Result handleFeignException(FeignException e) {
log.error("服务调用异常: {}", e.contentUTF8());
return Result.fail(ErrorCode.SERVICE_UNAVAILABLE);
}
// 兜底异常处理
@ExceptionHandler(Exception.class)
public Result handleException(Exception e) {
log.error("系统异常: {}", e.getMessage());
return Result.fail(ErrorCode.SYSTEM_ERROR);
}
}
关键点:通过@ControllerAdvice实现三层防护,特别注意对Feign异常的单独处理,保留原始错误信息
二、服务间调用异常处理
- Feign+Sentinel双保险配置:
feign:
client:
config:
default:
connectTimeout: 3000
readTimeout: 5000
sentinel:
scg:
fallback:
mode: response
response-body: '{"code":503,"msg":"服务降级"}'
- 自定义FallbackFactory:
@Component
public class OrderServiceFallbackFactory implements FallbackFactory<OrderServiceClient> {
@Override
public OrderServiceClient create(Throwable cause) {
return new OrderServiceClient() {
@Override
public Result<OrderDTO> getOrder(String orderId) {
if(cause instanceof BizException){
return Result.fail(((BizException) cause).getErrorCode(), "订单服务异常");
}
return Result.fail(ErrorCode.SERVICE_DEGRADE);
}
};
}
}
实战经验:在双十一大促中,这种组合策略帮助我们拦截了70%以上的级联故障
三、分布式事务异常处理
使用Seata的TCC模式示例:
@LocalTCC
public interface OrderTccAction {
@TwoPhaseBusinessAction(name = "prepareCreateOrder", commitMethod = "commit", rollbackMethod = "rollback")
boolean prepare(BusinessActionContext actionContext,
@BusinessActionContextParameter(paramName = "order") Order order);
boolean commit(BusinessActionContext actionContext);
boolean rollback(BusinessActionContext actionContext);
}
补偿策略:
- 自动重试:对网络抖动等临时性错误
- 人工干预:对数据不一致等严重问题
- 事务日志:记录关键操作节点
四、流量洪峰应对策略
- Resilience4j熔断配置:
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50)
.waitDurationInOpenState(Duration.ofMillis(1000))
.ringBufferSizeInHalfOpenState(2)
.ringBufferSizeInClosedState(2)
.build();
- 自适应限流算法:
@Slf4j
public class AdaptiveLimiter {
private AtomicInteger currentLimit = new AtomicInteger(100);
public boolean tryAcquire() {
int current = currentLimit.get();
if(current <= 0) return false;
// 根据RT和成功率动态调整
double successRate = getRecentSuccessRate();
long avgRT = getAvgResponseTime();
if(successRate < 90% || avgRT > 500ms) {
currentLimit.updateAndGet(x -> Math.max(x/2, 10));
} else if(successRate > 99% && avgRT < 100ms) {
currentLimit.updateAndGet(x -> Math.min(x*2, 1000));
}
return true;
}
}
五、异常追踪三板斧
- 全链路追踪:
@Slf4j
public class TraceInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
MDC.put("traceId", UUID.randomUUID().toString());
}
}
- 异常画像系统:
@Aspect
@Component
public class ExceptionMonitor {
@AfterThrowing(pointcut = "execution(* com..*.*(..))", throwing = "ex")
public void monitorException(Exception ex) {
ExceptionMetric metric = new ExceptionMetric(
ex.getClass().getSimpleName(),
Thread.currentThread().getName(),
System.currentTimeMillis()
);
KafkaTemplate.send("exception_metrics", metric);
}
}
- 智能告警:基于ELK的异常模式识别
总结
在分布式系统中,异常处理不是简单的try-catch,而是需要建立完整的防御体系:
- 全局异常拦截:统一异常出口
- 服务治理:熔断/限流/降级三板斧
- 事务补偿:最终一致性保障
- 智能监控:快速定位问题根源
当系统吞吐量从100TPS提升到5000TPS时,我们的异常处理体系经受住了真实流量的考验。记住:好的异常处理方案,不是消灭异常,而是让系统优雅地与之共处。