1대의 서버 애플리케이션은 최대 몇 개의 동시 요청을 감당할 수 있을까?
Overview
Spring MVC 웹 애플리케이션은 동시 사용자를 몇 명까지 수용할 수 있을까? 🤔
자신이 만든 서버가 어떤 상태여야 많은 유저를 수용하면서 안정적인 서비스를 제공할 수 있을지에 대한 대략적인 수치를 가늠하기 위해 Spring MVC 의 tomcat 설정을 중심으로 네트워크의 변화를 살펴봅니다.
이후는 작성의 편의를 위해 문어체를 사용합니다 🙏
기술적인 오류나 오타 등의 잘못된 내용이 있다면 댓글로 알려주시면 감사하겠습니다 🙇♂️
Test Scenario
- 동시에 200명 이상의 사용자가 API 를 요청하는 상황을 가정
- 해당 API 가 너무 빨리 응답하는 것을 방지하고, 어느 정도의 지연을 모의하기 위해 5초의 대기시간을 갖도록 구현
- Spring MVC 의 tomcat 설정을 조절해가면서 트래픽 처리량을 검증
- 테스트 데이터의 오염을 방지하기 위해 API 는 EC2 에 배포해놓은 상태에서, 로컬에서 부하를 발생
Environment
- EC2 t4g.small (Amazon Linux 2core 2GB 64bit ARM)
- SpringBoot 3.1.5
- Spring MVC
- Spring Actuator
- K6
Test Application
먼저 API 를 간단하게 구현한다.
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() throws InterruptedException {
TimeUnit.SECONDS.sleep(5); // 처리 시간을 시뮬레이션
return "Hello, World!";
}
}
어느 정도 오버로드가 발생하는 API 라고 가정하기 위해 5초의 지연 시간을 주었다. 지연 시간이 없다면 요청이 너무 빠르게 처리되어 네트워크 동작을 확인하기 어려울 수 있다. 이번 글에서 조절할 설정은 다음과 같다.
server:
tomcat:
threads:
max: 200 # 생성할 수 있는 thread의 총 개수
max-connections: 8192 # 수립가능한 connection의 총 개수
accept-count: 100 # 작업큐의 사이즈
connection-timeout: 20000 # timeout 판단 기준 시간, 20초
서버에서의 원활한 설정값 수정을 위해 모든 부분을 시스템 환경변수로 대체한다.
server:
tomcat:
threads:
max: ${TOMCAT_MAX_THREADS:200}
max-connections: ${TOMCAT_MAX_CONNECTIONS:8192}
accept-count: ${TOMCAT_ACCEPT_COUNT:100}
connection-timeout: ${TOMCAT_CONNECTION_TIMEOUT:20000}
Docker Image 를 빌드하기 위해 Dockerfile 을 작성한다.
# java 17 multi stage build
FROM gradle:8.4.0-jdk17 as builder
WORKDIR /app
COPY . .
RUN gradle clean build
FROM openjdk:17-ea-11-jdk-slim
WORKDIR /app
COPY /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
docker build -t sample-server .
테스트를 위한 애플리케이션 준비는 거의 다 됐다. 이후는 적당한 registry 에 이미지를 push 하고, EC2 에서 docker run
을 실행하기만 하면 된다. 분량상 EC2 를 생성하고 이미지를 배포하는 과정은 생략한다.
K6
K6 는 Grafana Lab 에서 만든 현대적인 부하테스트 툴이다. JavaScript 로 테스트 시나리오를 작성할 수 있으며, 굉장히 다양한 상황을 모의하여 테스트할 수 있다. Apache JMeter 또한 이번 테스트를 위해 사용할 수 있는 좋은 옵션 중 하나이지만, K6 는 테스트 결과를 시각화해줄 Grafana 와 통합하기 좋고 사용법이 어렵지 않아 쉽게 다양한 상황을 검증해볼 수 있다. 따라서 이번 테스트를 위해서는 K6 를 사용하기로 한다. 최근은 특히 JMeter 보다는 K6 를 먼저 고려하고 있다.
K6 설치
brew install k6
모니터링 구성
도커 컴포즈로 Grafana 와 InfluxDB 를 간단하게 실행해준다.
version: "3.7"
services:
influxdb:
image: bitnami/influxdb:1.8.5
container_name: influxdb
ports:
- "8086:8086"
- "8085:8088"
environment:
- INFLUXDB_ADMIN_USER_PASSWORD=bitnami123
- INFLUXDB_ADMIN_USER_TOKEN=admintoken123
- INFLUXDB_HTTP_AUTH_ENABLED=false
- INFLUXDB_DB=myk6db
granafa:
image: bitnami/grafana:latest
ports:
- "3000:3000"
docker compose up -d
InfluxDB 가 정상동작하는지 확인해보자. 만약 아래 명령어가 실행되지 않는다면, brew install influxdb-cli
를 통해 커맨드를 먼저 설치해줘야 한다.
influx ping
# OK
http://localhost:3000 으로 접근하여 그라파나가 정상적으로 동작하는 것을 확인한다.
Grafana 의 초기 계정정보는 아이디와 비밀번호 모두 admin 을 입력하면 된다. 비밀번호를 변경하라고 나오겠지만, 이번에 그라파나를 사용하는 이유는 운영이 아니라 테스트이므로 skip 해도 무방할 것이다.
InfluxDB 를 datasource 로 설정한 뒤 K6 dashboard URL 을 복사하여 import 해주면 모니터링 구성이 완료된다.
5분이면 모니터링 환경 구성 끝...!