MST

星途 面试题库

面试题:Java RESTful API异常处理之分布式场景

在分布式系统中使用Java开发RESTful API,不同服务之间调用可能会出现各种异常。比如网络波动导致的服务间通信超时、服务节点故障等。请设计一套完整的异常处理和容错机制,涵盖异常的跨服务传播、统一的异常编码和消息处理,以及如何在分布式环境下实现优雅降级和熔断,给出详细的架构设计和关键代码片段。
31.8万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

异常处理和容错机制架构设计

1. 异常的跨服务传播

  • 采用HTTP状态码:利用HTTP协议的状态码来传递异常信息。例如,408表示请求超时(对应服务间通信超时场景),500表示服务器内部错误(对应服务节点故障等一般性错误)。在RESTful API中,服务端在捕获异常时,根据异常类型设置合适的HTTP状态码返回给调用方。
  • 自定义异常头:除了HTTP状态码,还可以在HTTP头中自定义字段来传递更详细的异常信息。例如,添加 X-Error-Code 字段用于传递异常编码,X-Error-Message 字段用于传递异常消息。这样,调用方在接收到响应时,可以根据这些自定义头信息进行进一步处理。

2. 统一的异常编码和消息处理

  • 异常编码体系:设计一套统一的异常编码体系,每个异常类型对应一个唯一的编码。例如,通信超时异常编码为 1001,服务节点故障异常编码为 2001 等。这些编码在整个分布式系统中保持一致,便于各个服务进行识别和处理。
  • 异常消息管理:为每个异常编码定义对应的消息模板。可以将这些消息模板存储在配置文件或数据库中,便于集中管理和维护。当捕获到异常时,根据异常编码从配置中获取对应的消息内容,并根据需要进行参数替换等操作,以生成最终的异常消息返回给调用方。

3. 优雅降级和熔断

  • 优雅降级
    • 业务逻辑实现:在服务实现中,针对关键业务逻辑,添加降级逻辑。例如,当某个依赖服务不可用时,返回默认数据或执行简化的业务逻辑。可以通过配置文件或动态配置中心来控制降级逻辑的启用和禁用。
    • 监控与动态调整:建立监控系统,实时监测服务的性能和可用性指标。根据监控数据,动态调整降级策略。例如,如果某个服务的响应时间持续增长,可以自动启用降级逻辑,以保证整体系统的可用性。
  • 熔断
    • 熔断器模式:采用熔断器模式,如Hystrix。在服务调用过程中,通过熔断器来监控服务的调用情况。当失败次数或失败率达到一定阈值时,熔断器打开,后续请求不再调用实际服务,而是直接返回降级响应。
    • 恢复机制:熔断器打开一段时间后,进入半开状态,尝试少量请求调用实际服务。如果调用成功,则熔断器关闭,恢复正常调用;如果再次失败,则继续保持打开状态。

关键代码片段

1. 异常的跨服务传播

  • Spring Boot示例
@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. 优雅降级和熔断

  • Hystrix示例(优雅降级和熔断)
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();
    }
}