programing

스프링 부츠 콜드 스타트

css3 2023. 10. 2. 15:22

스프링 부츠 콜드 스타트

개방형 임시 클러스터의 도커 컨테이너 내부에서 실행 중인 스프링 부트 애플리케이션이 있습니다.정상 상태에서는 N개의 애플리케이션 인스턴스가 존재하며(예: N=5), 이러한 N개의 인스턴스에 대한 요청이 로드 밸런싱됩니다.모든 것이 정상적으로 실행되고 응답 시간이 짧습니다(총 처리량 ~60k로 ~5ms).

새 인스턴스를 추가할 때마다 응답 시간이 짧게(최대 70ms) 증가했다가 다시 정상으로 돌아갑니다.

이런 콜드 스타트를 피하기 위해 제가 할 수 있는 일이 있을까요?트래픽 전송 전에 순차적으로 ~100 컬콜을 하면서 앱 사전 워밍을 시도했는데, 도움이 되지 않았나요?

동시성이 높은 더 나은 워밍업 스크립트가 필요합니까?더 나은 방법이 없을까요?

감사해요.

마이크로 서비스에서 유사한 문제가 발생했습니다. 워밍업을 위해 컴포넌트를 추가했습니다.

ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> 

애플리케이션 내에서, 이것은 우리에게 효과가 있었습니다. 이 해결책으로, 당신이 시작하는 모든 인스턴스에서 당신의 페이로드에 사용될 모든 클래스는 인스턴스의 시작 직후에 로드될 것이고 당신은 호출을 하기 위해 외부 스크립트가 필요하지 않습니다.또한 외부 스크립트의 문제는 새로운 인스턴스에 의해 처리되는 호출에 대해 확실하게 말할 수 없습니다.

@Component
public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {

    @Autowired
    YourService yourService;

    @Override
    public void onApplicationEvent(final ApplicationReadyEvent event) {

        System.out.println("ApplicationReadyEvent: application is up");
        try {
            // some code to call yourservice with property driven or constant inputs 
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


} 

요청을 제공할 때 응용프로그램이 정상적이지만 응답 속도가 느릴 때 여전히 문제가 있는 경우 계층화 컴파일을 사용하도록 설정해야 합니다.

-XX:CompileThreshold -XX:TieredCompilation

일반적으로 VM은 컴파일러에 입력되는 메서드에 대한 프로파일링 정보를 수집하기 위해 인터프리터를 사용합니다.계층 구조에서는 인터프리터 외에도 클라이언트 컴파일러를 사용하여 자신에 대한 프로파일링 정보를 수집하는 컴파일된 버전의 메서드를 생성합니다.

컴파일된 코드는 해석된 코드보다 상당히 빠르기 때문에, 프로그램은 프로파일링 단계에서 더 나은 성능으로 실행됩니다.

이 문제는 두 가지 측면에서 해결할 수 있습니다.첫 번째 방법은 서빙하기 전에 몸을 따뜻하게 하는 것입니다.두 번째 방법은 초기에 외부로부터의 요청을 적게 하여 JVM의 초기화를 완료하기 위해 더 많은 컴퓨팅 리소스를 예약할 수 있도록 하는 것입니다(예: 클래스 로드).어느 쪽이든 시작하려면 JVM을 예열해야 하기 때문입니다.이것은 JVM의 작동 원리에 의해 결정됩니다.특히 HotSpot 가상 머신의 실행 엔진은 해석 실행 엔진과 실시간 컴파일 실행(JIT)의 두 부분으로 구성됩니다.바이트 코드를 실시간으로 컴파일하기 위해 CPU 리소스가 필요한 JIT의 경우.게다가, 게으른 수업 로딩 또한 첫 번째 실행에서 더 많은 시간을 요구할 것입니다.

  1. JVM 워밍업

JVM 웜업은 주로 클래스 로딩과 실시간 컴파일의 두 가지 문제를 해결하는 것입니다.

  • 클래스 로드의 경우 미리 덮어쓰기 코드 경로를 실행하기만 하면 됩니다.
  • JIT의 경우 일반적으로 서버측(JVM 서버 모드)에서 C1/C2와 같은 계층형 컴파일이 활성화됩니다.JDK7 이상을 사용하는 경우 계층형 컴파일이 기본적으로 사용됩니다(하위 버전의 JDK에는 JVM 매개 변수가 필요함: -XX:+TieredCompilation). C1과 C2의 컴파일 컴퓨팅 리소스가 다르며 C2에는 더 많은 리소스가 있습니다.예열의 목적은 C1/C2 컴파일을 트리거하여 공식 요청이 들어오면 코드가 예열되고 컴파일이 패스되도록 하는 것일 수 있습니다.

위 두 방향의 경우 클래스 로드 자체에 더 많은 시간이 소요됩니다.이 부분을 예열하면 입출력 비율이 높아집니다.

  1. 네트워크 계층 워밍업.

네트워크 수준에서 특정 웜업 트래픽이 제공되며, 이는 특정 웜업 트래픽 또는 일반 사용자 요청일 수 있습니다.

이것은 일반적으로 흐름 제어를 위해 nginx 계층에서 수행될 수 있습니다.새로 시작한 노드가 업스트림에 합류하면 새 노드에 매우 낮은 가중치를 부여할 수 있습니다.이런 방식으로 초기 단계에서 적은 양의 트래픽만 입력됩니다.따라서 충분한 컴퓨팅 리소스가 예약되어 있습니다.코드 웜업 즉, 클래스 로드 및 Just-in-time 컴파일을 수행하는 것입니다.서비스가 HTTP 서비스가 아닌 RPC 서비스만 제공하는 경우 RPC 프레임워크 계층은 트래픽 예열을 수행할 수 있습니다.예를 들어, Dubbo와 같은 RPC 프레임워크에는 이미 서비스 예열 기능이 있습니다.마찬가지로 예열은 시작 초기 단계의 노드가 적은 양의 트래픽만 제공한다는 것을 의미합니다.

예열에 필요한 컴퓨팅 리소스들은 상기 방법들에서 언급됩니다.즉, CPU입니다. 서비스 호스트에 충분한 컴퓨팅 리소스가 있으면 각 노드에 더 많은 CPU 리소스를 할당하여 예열 프로세스 속도를 높일 수 있습니다.예열 처리 시간을 줄입니다.

위 네트워크 계층 및 하드웨어 자원과 RPC 프레임워크를 변경할 수 없는 경우.우리는 스프링부트 마이크로 서비스 안에서 몸을 녹일 수 있습니다.했습니다에 언급하였습니다.ApplicationReadyEvent, 실제 더 나은 구현은 듣는 것입니다.ContextRefreshedEventevent. ApplicationReadyEvent가 발생하면 HTTP 포트가 초기화되고 노출되기 때문입니다.워밍업이 완료되기 전에 예상치 못한 요청이 들어올 수 있습니다.

@Component
public class StartWarmUpListener implements ApplicationListener<ContextRefreshedEvent> {
    /**
     * Handle an application event.
     *
     * @param event the event to respond to
     */
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // do something about warm-up here.....
    }
}

참고: 위의 워밍업 코드가 모든 코드를 워밍업하는 것은 아닙니다.컨트롤러 계층의 요청에는 HTTP 서버가 준비되지 않을 때까지 실제로 실행할 수 없는 일부 코드 경로가 있기 때문입니다.우리는 서비스 계층에서만 코드 커버리지를 수행할 수 있습니다.간단히 말해서, 이것은 타협일 수도 있습니다.

제 시나리오에서는 클라이언트 풀을 초기화하거나 캐시를 미리 로드하거나 다른 게으른 로드 작업자에게 100 이상의 컬 요청을 모의합니다.

저는 이 일을 합니다.WarmupHealthIndicator implements HealthIndicator스프링 액추에이터 상태 점검 엔드포인트를 구현합니다.

마지막으로 워밍업이 완료되기 전에 Nginx(또는 다른 로드 밸런서)의 힐 체크는 5xx 상태 코드와 본문 메시지 아래에 표시됩니다.또한 상태가 업 된 후에는 앱 초기화에 시간이 소요되는 트래픽이 없습니다.

{
  "status": "DOWN",
  "details": {
    "warmup": {
      "status": "DOWN"
    },
    "diskSpace": {
      "status": "UP",
      "details": {
        "total": 536608768000,
        "free": 395195826176,
        "threshold": 10485760
      }
    }
  }
}

게다가.NGINX Plus당신의 흥미를 위해 같은 일을 할 수 있는 유료 기능 slow_start를 가지고 있습니다.

우선 J를 활성화 시키려고 합니다.IT 컴파일 및 결과 비교.Baeldung에는 기본 C1 및 C2 JIT 컴파일러와 Graal 성능을 비교하는 좋은 기사가 있습니다. 워크로드에 대한 테스트를 실행하는 것이 좋습니다.기본적으로 Java 애플리케이션을 실행할 때 다음 옵션을 설정해야 합니다.

-XX:+Experimental VM 옵션 잠금 해제 -XX:+사용JVMCI -XX:+JVMCI 컴파일러 사용

또한 OpenShift에서 Spring Boot의 액추에이터 상태 점검 URL(/actuator/health)을 사용하여 준비 프로브를 구성했는지 확인합니다.그렇지 않으면 컨테이너가 서비스 준비 전에 트래픽을 수신할 수 있습니다.

준비 상태 프로브는 컨테이너가 요청을 처리할 준비가 되었는지 여부를 결정합니다.준비 프로브가 컨테이너에 실패하면 엔드포인트 컨트롤러는 컨테이너의 IP 주소가 모든 서비스의 엔드포인트에서 제거되도록 합니다.준비 프로브를 사용하여 엔드포인트 컨트롤러에 컨테이너가 실행 중이라도 프록시로부터 트래픽을 수신해서는 안 된다는 신호를 보낼 수 있습니다.포드 구성의 template.spec.containers.readyprobestanza를 구성하여 준비 상태 검사를 설정합니다.

마지막으로 응답이 NGINX나 다른 역방향 프록시에 의해 캐시되는 것도 도움이 됩니다.

스프링 부트 응용 프로그램이 시작되면 초기화를 위해 JVM이 다양한 클래스를 로드해야 하므로 HTTP 요청에 대한 응답 시간이 길어집니다.

http 구성 요소를 워밍업하려면 다음을 참조할 수 있습니다.

@Component
public class WarmUpListener implements ApplicationListener<ApplicationReadyEvent> {
    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        // Warm up
    }
}

또는 이 스프링 부트 스타터를 사용해 보십시오. warmup-spring-boot-starter, HTTP 관련 구성 요소는 응용 프로그램이 외부 서비스를 제공하기 전에 예열할 수 있습니다.

언급URL : https://stackoverflow.com/questions/54759652/spring-boot-cold-start