Spring Boot의 Actuator를 사용하여 백엔드 서비스 회로 차단기를 만들어보십시오 (전편)

전제 조건



시스템 개발을 하고 있으면, 「백엔드 서비스가 고장나 에러를 돌려주기 시작했다고 해도 뭔가 좋은 느낌으로 동작해 시스템 전체가 불안정하게 되지 않게 해 주세요」라든지 무차 흔들리는 일, 있다 그렇지?

그럴 때 자전에서 동작을 생각하는 것이 귀찮기 때문에 Spring Boot의 기능을 쓰러뜨리고 회로 차단기에 할 수 있을까 실험해 보았다.

결국 AWS에서 좋은 느낌으로 움직이도록 해보고 싶지만, 전반은 구현 방법까지.

Spring Boot 준비



우선, 웹 앱으로서 최소한으로 움직여 주면 좋기 때문에, 템플릿으로부터 빈 스타터 프로젝트를 작성한다.

pom.xml에는, 디폴트 이외에 이하의 의존관계를 설정해 두자.

pom.xml
    <dependencies>
        ……
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        ……
    </dependencies>

RestController에 대해서는, 이번 본제의 부분이 아니기 때문에 텍토. 최소 구성으로 다음과 같은 느낌으로.

WebController.java
package com.example;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WebController {

  @RequestMapping("/hello")
  public String hello() {
    return "hello()";
  }

}

백엔드 서비스에 대한 상태 확인 추가 정의



여기에서 Spring Boot 문서을 읽고 있습니다.

백엔드 서비스에 대한 상태 확인을 사용자 지정 상태 확인으로 등록합니다.
이번에는, 제어가 편해지도록 백엔드 서비스를 Lambda 함수로 해 실험하고 있으므로, 헬스 체크의 이름에 Lambda가 들어가 있지만, 적절히 좋아하는 이름으로 변경해 주시면.

HealthIndicator 인터페이스를 다음과 같은 느낌으로 구현한다.
이렇게 하면, 기동시에 자동적으로 Bean에 등록되어 주는 것 같다. 자세한 메커니즘은 이해할 수 없습니다. 제대로 공부하지 않으면.

LambdaHealthIndicator.java
package com.example;

import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.stereotype.Component;
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.IOException;

@Component
public class LambdaHealthIndicator implements HealthIndicator {

  @Override
  public Health health() {
    int statusCode = check();
    if (statusCode != HttpURLConnection.HTTP_OK) {
      return Health.down().withDetail("HTTP Request Error", statusCode).build();
    } else {
      return Health.up().withDetail("HTTP Request Success", statusCode).build();
    }
  }

  private int check(){
    String strUrl = "Lambda関数のぶら下がったALB/NLB/API GatewayのURL";
    URL url = null;
    HttpURLConnection  urlConn = null;
    int statusCode = 200;

    try {
      url = new URL(strUrl);
      urlConn = (HttpURLConnection) url.openConnection();
      urlConn.setRequestMethod("GET");
      urlConn.connect();
      statusCode = urlConn.getResponseCode();   
    } catch (IOException e) {
      e.printStackTrace();
      statusCode = 503;
    } finally {
      if (urlConn != null) {
        urlConn.disconnect();
      }
    }
    return statusCode;
  }
}

글쎄, 이것만이라면 Acutuator의 기본보기에서 /actuator/health에 액세스하더라도
{"status":"UP"}

라고 밖에 돌려주지 않는다. 다음과 같은 느낌으로 어플리케이션 프로퍼티를 편집해 둘 필요가 있다.

application.properties
management.endpoint.health.show-details=always
management.health.defaults.enabled=false
management.health.lambda.enabled=true

1행째는, 헬스 체크의 내용을 상세 표시하기 위한 옵션.
2행째는, true로 되어 있으면, diskspace라고도 표시되어 버려 보기 어렵기 때문에, 이 기사중에서는 무효로 한다.
세 번째 줄은 추가 된 LambdaHealthIndicator를 활성화합니다. 문서에도 쓰여져 있지만, HealthIndicator의 접두구가 설정치로서 취급되는 것 같다.

실험해보기



위의 앱을 실행하고 http://localhost:8080/actuator/health에 액세스하면,
{"status":"UP","components":{"lambda":{"status":"UP","details":{"HTTP Request Success":200}}}}

라고 표시된다.
여기서 백엔드의 Lambda 함수의 설정에서 스로틀링(=동시 실행의 예약:0으로 한다)을 하고, ALB로부터 502 응답이 돌아오는 상태로 하면,
{"status":"DOWN","components":{"lambda":{"status":"DOWN","details":{"HTTP Request Error":502}}}}

되어 제대로 에러를 검지하고 있다.
Chrome의 개발자 도구에서 헤더를 확인해 보면,



응답 코드도 503이 되어 있으므로, 헬스 체크를 여기에 향하는 것으로 회로 브레이커로서 취급할 수 있는 것이 아닐까!

좋은 웹페이지 즐겨찾기