首頁  >  文章  >  Java  >  Spring Boot 微服務中的進階錯誤處理

Spring Boot 微服務中的進階錯誤處理

Patricia Arquette
Patricia Arquette原創
2024-10-28 19:02:30431瀏覽

Advanced Error Handling in Spring Boot Microservices

在複雜的微服務中,進階錯誤處理不僅僅是簡單的異常日誌記錄。有效的錯誤處理對於可靠性、可擴展性和保持良好的使用者體驗至關重要。本文將介紹 Spring Boot 微服務中錯誤處理的高級技術,重點介紹管理分散式系統中的錯誤、處理重試、建立自訂錯誤回應以及以方便偵錯的方式記錄錯誤的策略。

1. Spring Boot 中的基本錯誤處理

讓我們從 Spring Boot 中的基本錯誤處理方法開始來設定基準。

1.1 使用@ControllerAdvice和@ExceptionHandler

Spring Boot 透過 @ControllerAdvice 和 @ExceptionHandler 提供了全域例外處理程序。此設定使我們能夠在一個地方處理所有控制器的異常。

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred.");
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

這裡,ErrorResponse 是自訂錯誤模型:

public class ErrorResponse {
    private String code;
    private String message;

    // Constructors, Getters, and Setters
}

1.2 回傳一致的錯誤回應

確保所有異常回傳一致的錯誤回應格式(例如 ErrorResponse)有助於客戶端正確解釋錯誤。


2.錯誤處理的高階技術

2.1 使用錯誤 ID 進行集中記錄和追蹤

為每個異常分配唯一的錯誤 ID 有助於跨服務追蹤特定錯誤。此 ID 也可以與異常詳細資訊一起記錄,以便於調試。

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
    String errorId = UUID.randomUUID().toString();
    log.error("Error ID: {}, Message: {}", errorId, ex.getMessage(), ex);

    ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", 
                                             "An unexpected error occurred. Reference ID: " + errorId);
    return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}

客戶端收到包含 errorId 的錯誤回應,他們可以將其報告給支援人員,並將其直接連結到詳細日誌。

2.2 增加瞬態錯誤的重試邏輯

在分散式系統中,暫時性問題(例如網路逾時)可以透過重試來解決。使用Spring的@Retryable對服務方法進行重試邏輯。

設定

首先,在 pom.xml 中加入 Spring Retry 相依性:

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

然後,使用@EnableRetry啟用Spring Retry,並註解需要重試的方法。

@EnableRetry
@Service
public class ExternalService {

    @Retryable(
        value = { ResourceAccessException.class },
        maxAttempts = 3,
        backoff = @Backoff(delay = 2000))
    public String callExternalService() throws ResourceAccessException {
        // Code that calls an external service
    }

    @Recover
    public String recover(ResourceAccessException e) {
        log.error("External service call failed after retries.", e);
        return "Fallback response due to error.";
    }
}

此配置最多重試該方法 3 次,每次嘗試之間延遲 2 秒。如果所有嘗試都失敗,則復原方法將作為後備執行。

2.3 在微服務中使用具有回退功能的 Feign 用戶端

對於服務到服務呼叫中的錯誤處理,Feign 提供了一種宣告式方式來設定重試和回退。

假裝配置

定義一個具有後備支援的 Feign 用戶端:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleResourceNotFound(ResourceNotFoundException ex) {
        ErrorResponse error = new ErrorResponse("NOT_FOUND", ex.getMessage());
        return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
        ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", "An unexpected error occurred.");
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

此方法可確保如果庫存服務不可用,InventoryServiceFallback 會啟動預先定義的回應。


3.錯誤記錄與可觀察性

3.1 使用 ELK Stack 集中日誌記錄

設定 ELK(Elasticsearch、Logstash、Kibana)堆疊來整合來自多個微服務的日誌。借助集中式日誌系統,您可以輕鬆追蹤服務中的問題並查看帶有關聯錯誤 ID 的日誌。

例如,在application.yml中設定日誌模式:

public class ErrorResponse {
    private String code;
    private String message;

    // Constructors, Getters, and Setters
}

3.2 使用 Spring Cloud Sleuth 新增追蹤 ID

在分散式系統中,跨多個服務追蹤單一事務至關重要。 Spring Cloud Sleuth 提供具有唯一追蹤和跨度 ID 的分散式追蹤。

在您的依賴項中加入 Spring Cloud Sleuth:

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGeneralException(Exception ex) {
    String errorId = UUID.randomUUID().toString();
    log.error("Error ID: {}, Message: {}", errorId, ex.getMessage(), ex);

    ErrorResponse error = new ErrorResponse("INTERNAL_SERVER_ERROR", 
                                             "An unexpected error occurred. Reference ID: " + errorId);
    return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}

4. REST API 的自訂錯誤處理

4.1 建立自訂異常類別

定義自訂異常以提供更具體的錯誤處理。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

4.2 自訂錯誤回應結構

透過實作 ErrorAttributes 來客製化錯誤回應,以獲取結構化和豐富的錯誤訊息。

@EnableRetry
@Service
public class ExternalService {

    @Retryable(
        value = { ResourceAccessException.class },
        maxAttempts = 3,
        backoff = @Backoff(delay = 2000))
    public String callExternalService() throws ResourceAccessException {
        // Code that calls an external service
    }

    @Recover
    public String recover(ResourceAccessException e) {
        log.error("External service call failed after retries.", e);
        return "Fallback response due to error.";
    }
}

在設定中註冊 CustomErrorAttributes 以自動自訂所有錯誤回應。

4.3 API 錯誤回應標準化及問題詳細資料 (RFC 7807)

使用問題詳細資訊格式來實作標準化 API 錯誤結構。基於 RFC 7807 定義錯誤回應模型:

@FeignClient(name = "inventory-service", fallback = InventoryServiceFallback.class)
public interface InventoryServiceClient {
    @GetMapping("/api/inventory/{id}")
    InventoryResponse getInventory(@PathVariable("id") Long id);
}

@Component
public class InventoryServiceFallback implements InventoryServiceClient {

    @Override
    public InventoryResponse getInventory(Long id) {
        // Fallback logic, like returning cached data or an error response
        return new InventoryResponse(id, "N/A", "Fallback inventory");
    }
}

然後,從 @ControllerAdvice 方法傳回此結構化回應,以在所有 API 中保持一致的錯誤結構。

logging:
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

5.具有彈性的斷路器

整合式斷路器模式可以保護您的微服務免於重複呼叫失敗的服務。

使用 Resilience4j 斷路器
將 Resilience4j 加入您的依賴項:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>

然後,用斷路器包裝一個方法:

public class InvalidRequestException extends RuntimeException {
    public InvalidRequestException(String message) {
        super(message);
    }
}

如果多次失敗,此設定將停止呼叫 getInventory,並且 inventoryFallback 傳回安全回應。


結論

Spring Boot 微服務中的進階錯誤處理包括:

集中錯誤處理以實現一致的回應和簡化的偵錯。
重試和斷路器用於彈性服務到服務呼叫。
使用 ELK 和 Sleuth 等工具進行集中日誌記錄和可追溯性
自訂錯誤格式包含問題詳細資訊和結構化錯誤回應。
這些技術有助於確保您的微服務穩健,提供一致、可追蹤的錯誤回應,同時防止跨服務發生級聯故障。

以上是Spring Boot 微服務中的進階錯誤處理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn