异常处理和容错机制架构设计
1. 异常的跨服务传播
- 采用HTTP状态码:利用HTTP协议的状态码来传递异常信息。例如,408表示请求超时(对应服务间通信超时场景),500表示服务器内部错误(对应服务节点故障等一般性错误)。在RESTful API中,服务端在捕获异常时,根据异常类型设置合适的HTTP状态码返回给调用方。
- 自定义异常头:除了HTTP状态码,还可以在HTTP头中自定义字段来传递更详细的异常信息。例如,添加
X-Error-Code
字段用于传递异常编码,X-Error-Message
字段用于传递异常消息。这样,调用方在接收到响应时,可以根据这些自定义头信息进行进一步处理。
2. 统一的异常编码和消息处理
- 异常编码体系:设计一套统一的异常编码体系,每个异常类型对应一个唯一的编码。例如,通信超时异常编码为
1001
,服务节点故障异常编码为 2001
等。这些编码在整个分布式系统中保持一致,便于各个服务进行识别和处理。
- 异常消息管理:为每个异常编码定义对应的消息模板。可以将这些消息模板存储在配置文件或数据库中,便于集中管理和维护。当捕获到异常时,根据异常编码从配置中获取对应的消息内容,并根据需要进行参数替换等操作,以生成最终的异常消息返回给调用方。
3. 优雅降级和熔断
- 优雅降级:
- 业务逻辑实现:在服务实现中,针对关键业务逻辑,添加降级逻辑。例如,当某个依赖服务不可用时,返回默认数据或执行简化的业务逻辑。可以通过配置文件或动态配置中心来控制降级逻辑的启用和禁用。
- 监控与动态调整:建立监控系统,实时监测服务的性能和可用性指标。根据监控数据,动态调整降级策略。例如,如果某个服务的响应时间持续增长,可以自动启用降级逻辑,以保证整体系统的可用性。
- 熔断:
- 熔断器模式:采用熔断器模式,如Hystrix。在服务调用过程中,通过熔断器来监控服务的调用情况。当失败次数或失败率达到一定阈值时,熔断器打开,后续请求不再调用实际服务,而是直接返回降级响应。
- 恢复机制:熔断器打开一段时间后,进入半开状态,尝试少量请求调用实际服务。如果调用成功,则熔断器关闭,恢复正常调用;如果再次失败,则继续保持打开状态。
关键代码片段
1. 异常的跨服务传播
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(TimeoutException.class)
@ResponseStatus(HttpStatus.REQUEST_TIMEOUT)
@ResponseBody
public ErrorResponse handleTimeoutException(TimeoutException ex) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setErrorCode("1001");
errorResponse.setErrorMessage("服务间通信超时");
return errorResponse;
}
@ExceptionHandler(ServiceNodeFailureException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
@ResponseBody
public ErrorResponse handleServiceNodeFailureException(ServiceNodeFailureException ex) {
ErrorResponse errorResponse = new ErrorResponse();
errorResponse.setErrorCode("2001");
errorResponse.setErrorMessage("服务节点故障");
return errorResponse;
}
}
class ErrorResponse {
private String errorCode;
private String errorMessage;
// getters and setters
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
}
2. 统一的异常编码和消息处理
public class ExceptionMessageUtil {
private static final Map<String, String> errorMessageMap = new HashMap<>();
static {
errorMessageMap.put("1001", "服务间通信超时");
errorMessageMap.put("2001", "服务节点故障");
}
public static String getErrorMessage(String errorCode) {
return errorMessageMap.get(errorCode);
}
}
3. 优雅降级和熔断
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
public class ExampleService {
public String callRemoteService() {
return new HystrixCommand<String>(HystrixCommandGroupKey.Factory.asKey("ExampleGroup")) {
@Override
protected String run() throws Exception {
// 实际调用远程服务的代码
return "Remote service response";
}
@Override
protected String getFallback() {
// 降级逻辑
return "Default response (fallback)";
}
}.execute();
}
}