1. 개요
이 기사에서는 잘 알려진 두 가지 Java 프레임워크인 Spring Boot와 Quarkus를 간단하게 비교합니다. 끝에서 우리는 차이점과 유사점 및 몇 가지 특수성을 더 잘 이해할 것입니다.
또한 성능을 측정하고 동작을 관찰하기 위해 몇 가지 테스트를 수행합니다.
2. 스프링 부트
Spring Boot는 엔터프라이즈 애플리케이션에 중점을 둔 Java 기반 프레임워크입니다 . 모든 Spring 프로젝트를 연결하고 많은 프로덕션 준비 통합을 제공하여 개발자의 생산성을 가속화하는 데 도움이 됩니다 .
이를 통해 구성 및 상용구의 양을 줄입니다. 또한 런타임의 클래스 경로에서 사용할 수 있는 의존성을 기반으로 기본 구성을 자동으로 등록하는 구성 방식에 대한 관례 덕분에 Spring Boot는 많은 Java 애플리케이션의 시장 출시 시간을 상당히 단축합니다.
3. 쿼커스
Quarkus는 위에서 언급한 Spring과 유사한 접근 방식을 사용하는 또 다른 프레임워크이지만 빠른 부팅 시간, 더 나은 리소스 활용 및 효율성으로 더 작은 아티팩트를 제공한다는 추가 약속이 있습니다 .
클라우드, 서버리스 및 컨테이너화된 환경에 최적화되어 있습니다. 그러나 이러한 약간 다른 초점에도 불구하고 Quarkus는 가장 널리 사용되는 Java 프레임워크와도 잘 통합됩니다.
4. 비교
위에서 언급했듯이 두 프레임워크는 다른 프로젝트 및 프레임워크와 잘 통합됩니다. 그러나 내부 구현 및 아키텍처는 다릅니다. 예를 들어 Spring Boot는 차단(서블릿) 및 비차단(WebFlux) 의 두 가지 방식으로 웹 기능을 제공합니다 .
반면 Quarkus는 두 가지 접근 방식을 모두 제공하지만 Spring Boot와 달리 차단 및 비차단 전략을 동시에 사용할 수 있습니다 . 또한 Quarkus는 아키텍처에 반응형 접근 방식을 내장하고 있습니다 .
이러한 이유로 Spring WebFlux 및 Quarkus 반응 기능으로 구현된 두 개의 완전히 반응하는 애플리케이션을 사용하여 비교에서 보다 정확한 시나리오를 가질 것입니다 .
또한 Quarkus 프로젝트에서 사용할 수 있는 가장 중요한 기능 중 하나는 네이티브 이미지(바이너리 및 플랫폼별 실행 파일)를 만드는 기능입니다. 따라서 비교에 두 네이티브 이미Map 포함하지만 Spring의 경우 네이티브 이미지 지원은 아직 실험 단계에 있습니다 . 이를 위해서는 GraalVM 이 필요합니다 .
4.1. 테스트 애플리케이션
우리의 애플리케이션은 세 가지 API를 노출할 것입니다. 하나는 사용자가 우편번호를 생성할 수 있도록 하고, 다른 하나는 특정 우편번호의 정보를 찾을 수 있도록 하며, 마지막으로 도시별로 우편번호를 쿼리합니다. 이러한 API는 이미 언급한 반응형 접근 방식과 MySQL 데이터베이스를 사용하여 Spring Boot와 Quarkus를 모두 사용하여 구현되었습니다.
목표는 간단한 샘플 애플리케이션을 만드는 것이었지만 HelloWorld 앱보다 조금 더 복잡했습니다. 물론 이것은 데이터베이스 드라이버 및 직렬화 프레임워크와 같은 구현이 결과에 영향을 미치기 때문에 비교에 영향을 미칠 것입니다. 그러나 대부분의 응용 프로그램은 이러한 사항도 처리할 수 있습니다.
따라서 우리의 비교는 어떤 프레임워크가 더 좋고 더 성능이 좋은지에 대한 궁극적인 사실이 아니라 이러한 특정 구현을 분석할 사례 연구를 목표로 합니다.
4.2. 테스트 계획
두 가지 구현을 테스트하기 위해 Wrk를 사용하여 테스트를 수행하고 메트릭 보고서를 사용하여 결과를 분석합니다. 또한 VisualVM 을 사용하여 테스트 실행 중에 애플리케이션의 리소스 사용률을 모니터링합니다.
테스트는 워밍업 기간부터 시작하여 100개에 도달할 때까지 연결 수를 늘린 후 모든 API가 호출되는 7분 동안 실행됩니다. Wrk는 이 설정으로 상당한 양의 로드를 생성할 수 있습니다.
모든 테스트는 다음 사양의 기계에서 수행되었습니다.
다른 백그라운드 프로세스와의 격리가 부족하기 때문에 이상적이지는 않지만 테스트는 제안된 비교를 설명하기 위한 것일 뿐입니다. 이미 언급한 것처럼 두 프레임워크의 성능에 대한 광범위하고 상세한 분석을 제공하려는 의도는 아닙니다.
언급할 가치가 있는 또 다른 요점은 기계 사양에 따라 연결 수, 스레드 등을 조정해야 할 수도 있다는 것입니다.
4.3. 우리의 테스트 알기
올바른 것을 테스트하고 있는지 확인하는 것이 중요하므로 이를 위해 Docker 컨테이너를 사용하여 인프라를 배포합니다. 이렇게 하면 응용 프로그램과 데이터베이스 모두의 리소스 제약 조건을 제어할 수 있습니다. 목표는 이제 기본 시스템인 데이터베이스인 응용 프로그램에 스트레스를 주는 것입니다. 이 예에서는 사용 가능한 CPU 수를 제한하는 것으로 충분하지만 시스템에서 사용 가능한 리소스에 따라 변경될 수 있습니다.
사용 가능한 소스를 제한하기 위해 Docker 설정 , cpulimit 명령 또는 선호하는 다른 도구를 사용할 수 있습니다. 또한 docker stats 및 top 명령을 사용하여 시스템 리소스를 모니터링할 수 있습니다. 마지막으로 메모리와 관련하여 힙 사용량과 RSS를 측정 하고 이를 위해 ps ( ps -o pid,rss,command -p <pid> ) 명령을 사용하겠습니다.
5. 결과
개발자 경험은 두 프로젝트 모두 훌륭했지만 Spring Boot에는 온라인에서 찾을 수 있는 것보다 더 나은 문서와 더 많은 자료가 있다는 점을 언급할 가치가 있습니다. Quarkus는 이 분야에서 개선되고 있으며 생산성을 높이는 데 도움이 되는 다양한 기능을 갖추고 있습니다. 그러나 문서 및 스택 오버플로 문제를 고려하면 여전히 뒤쳐져 있습니다.
메트릭 측면에서 다음이 있습니다.
이 실험을 통해 Quarkus가 JVM과 기본 버전 모두에서 시작 시간 측면에서 Spring Boot보다 빠르다는 것을 관찰할 수 있었습니다 . 또한 Quarkus 빌드 시간도 네이티브 이미지의 경우 훨씬 빨랐습니다. 빌드는 91초(Quarkus) VS 113초(Spring Boot), JVM 빌드는 5.24초(Quarkus) VS 1.75초(Spring Boot)가 걸렸습니다.
아티팩트 크기는 Spring Boot와 Quarkus에서 생성한 실행 가능한 아티팩트가 JVM 버전과 비슷했지만 네이티브의 경우 Quarkus가 더 잘 수행했습니다.
그러나 다른 메트릭과 관련하여 결론은 간단하지 않습니다. 이제 그들 중 일부를 더 자세히 살펴 보겠습니다.
5.1. CPU
CPU 사용량에 초점을 맞추면 JVM 버전이 워밍업 단계 초기 에 더 많은 CPU를 사용하는 것을 볼 수 있습니다. 그 후 CPU 사용량이 안정화되고 소비량은 모든 버전에서 상대적으로 동일해집니다.
다음은 JVM 및 네이티브 버전에서 순서대로 Quarkus의 CPU 소비량입니다.
(스프링 JVM)
(Quarkus JVM)
(Spring 네이티브)
(쿼커스 네이티브)
Quarkus는 두 경우 모두 더 잘했습니다. 그러나 그 차이가 너무 작아 동점도 고려할 수 있었습니다. 언급할 가치가 있는 또 다른 요점은 그래프에서 머신에서 사용 가능한 CPU 수를 기반으로 한 소비량을 볼 수 있다는 것입니다. 그래도 시스템의 다른 부분이 아닌 옵션을 강조하기 위해 애플리케이션에 사용할 수 있는 코어 수를 3개로 제한했습니다.
5.2. 메모리
메모리와 관련하여 훨씬 더 복잡합니다. 첫째, 두 프레임워크의 JVM 버전은 거의 동일한 양의 메모리를 힙에 더 많이 예약합니다 . 힙 사용량과 관련해서는 JVM 버전이 네이티브 버전보다 더 많은 메모리를 사용하지만 쌍으로 보면 Quarkus가 JVM 버전에서 Spring보다 약간 적게 사용하는 것 같습니다. 그러나 다시 말하지만 그 차이는 매우 작습니다.
(스프링 부트 JVM)
(Quarkus JVM)
그러다가 네이티브 이미지를 보니 뭔가 달라진 것 같다. Spring Native 버전은 메모리를 더 자주 수집하고 더 낮은 메모리 공간을 유지하는 것 같습니다 .
(스프링 부트 네이티브)
(쿼커스 네이티브)
또 다른 중요한 하이라이트는 Quarkus가 RSS 메모리 측정과 관련하여 두 버전 모두에서 Spring을 능가하는 것 같다는 것입니다. 시작 시 RSS 비교만 추가했지만 테스트 중에도 동일한 명령을 사용할 수 있습니다.
그럼에도 불구하고 이 비교에서는 기본 매개변수만 사용했습니다. 따라서 GC, JVM 옵션 또는 기타 매개변수는 변경되지 않았습니다. 응용 프로그램마다 다른 설정이 필요할 수 있으므로 실제 환경에서 사용할 때 이를 염두에 두어야 합니다.
5.3. 응답 시간
마지막으로 사용 가능한 많은 벤치마크 도구가 Coordinated Omission 이라는 문제로 인해 어려움을 겪고 있으므로 응답 시간과 관련하여 다른 접근 방식을 사용합니다 . 우리는 이 문제를 피하기 위해 고안된 도구인 하이퍼포일을 사용할 것입니다 . 테스트 중에 많은 요청이 생성되지만 아이디어는 응용 프로그램에 너무 많은 스트레스를 주지 않고 응답 시간을 측정하기에 충분합니다.
그러나 테스트 구조는 이전 구조와 거의 유사합니다.
(스프링 부트 JVM)
(Quarkus JVM)
처리량과 응답 시간은 서로 관련되어 있지만 같은 것이 아니며 서로 다른 것을 측정합니다. Quarkus JVM 버전은 압력이 가해질 때와 적당한 부하가 있을 때도 좋은 성능을 보였습니다. 처리량이 더 높고 응답 시간이 약간 더 짧은 것 같습니다.
(스프링 부트 네이티브)
(쿼커스 네이티브)
네이티브 버전을 보면 숫자가 다시 바뀝니다. 이제 Spring은 응답 시간이 약간 더 짧고 전반적으로 처리량이 더 높은 것으로 보입니다. 그러나 모든 숫자를 보면 그 차이가 너무 작아서 확실한 승자를 정의할 수 없다는 것을 알 수 있습니다.
5.4. 점들을 잇는
모든 것을 고려할 때 두 프레임워크 모두 Java 애플리케이션 구현을 위한 훌륭한 옵션임이 입증되었습니다.
네이티브 앱은 속도가 빠르고 리소스 소비가 적은 것으로 나타났으며 서버리스, 수명이 짧은 애플리케이션 및 낮은 리소스 소비가 중요한 환경에 탁월한 선택입니다.
반면에 JVM 앱은 오버헤드가 더 많은 것처럼 보이지만 시간이 지남에 따라 뛰어난 안정성과 높은 처리량을 제공하므로 견고하고 수명이 긴 애플리케이션에 이상적입니다.
마지막으로 성능과 관련하여 적어도 우리의 예에서는 모든 버전이 비교할 때 강력한 성능을 보입니다. 그 차이는 매우 미미하여 성능이 비슷하다고 말할 수 있습니다 . 물론 우리는 JVM 버전이 더 많은 리소스를 소비하면서 처리량 측면에서 무거운 부하를 더 잘 처리했으며 반면에 네이티브 버전은 덜 소비했다고 주장할 수 있습니다. 그러나 이 차이는 사용 사례에 따라 관련이 없을 수도 있습니다.
마지막으로 Spring 애플리케이션에서 설명서에서 권장하는 DB 드라이버에 문제가 있어서 DB 드라이버를 전환해야 했다는 점을 지적해야 합니다 . 반면 Quarkus는 아무 문제 없이 즉시 사용할 수 있었습니다.
6. 결론
이 기사에서는 Spring Boot 및 Quarkus 프레임워크와 서로 다른 배포 모드인 JVM 및 Native를 비교합니다. 또한 이러한 애플리케이션의 다른 메트릭과 측면도 살펴보았습니다. 평소와 같이 테스트 애플리케이션의 코드와 이를 테스트하는 데 사용되는 스크립트는 GitHub 에서 사용할 수 있습니다 .