Spring Boot 4 기반으로 HTTP, SSE, WebSocket 세 가지 통신 방식을 구현하고, Docker 격리 환경에서 서버 부하를 비교 측정하는 프로젝트입니다.
- Java 21
- Docker, Docker Compose
- curl
src/main/java/com/practice1/
├── http/
│ ├── MessageRequest.java # 요청 DTO
│ ├── HttpController.java # GET /api/hello, POST /api/message, GET /api/users/{id}
│ ├── HttpClientService.java # WebClient로 외부 API 호출 (동기/비동기)
│ └── HttpClientController.java # 외부 API 호출 엔드포인트
├── sse/
│ ├── SseController.java # SseEmitter 방식 SSE
│ └── SseFluxController.java # Flux 방식 SSE
├── websocket/
│ ├── WebSocketConfig.java # STOMP 설정
│ ├── ChatMessage.java # 채팅 DTO
│ └── ChatController.java # 채팅 메시지 브로드캐스트
├── benchmark/
│ ├── BenchmarkResult.java # 벤치마크 결과 DTO
│ ├── BenchmarkService.java # JVM 내부 부하 측정 로직
│ └── BenchmarkController.java # 벤치마크 엔드포인트
└── Practice1Application.java
src/main/resources/
├── static/
│ ├── sse.html # SSE 클라이언트 (브라우저)
│ └── chat.html # WebSocket 채팅 클라이언트 (브라우저)
└── application.yml
docker-compose up -d mysql./gradlew bootRun# HTTP
curl localhost:8080/api/hello
curl -X POST -H "Content-Type: application/json" -d '{"message":"test"}' localhost:8080/api/message
curl localhost:8080/api/users/1
# 외부 API 호출 (jsonplaceholder)
curl localhost:8080/api/external/posts/1/sync
curl localhost:8080/api/external/posts/1/async
# SSE — 브라우저에서 접속
open http://localhost:8080/sse.html
# WebSocket 채팅 — 브라우저에서 접속
open http://localhost:8080/chat.htmldocker-compose down
docker-compose build app
docker-compose up -ddocker-compose.yml에서 앱 컨테이너에 리소스 제한이 설정되어 있습니다:
deploy:
resources:
limits:
memory: 512m
cpus: "1.0"# health가 UP이 될 때까지 대기
curl localhost:8080/actuator/healthdocker stats practice1-app --no-stream출력 예시:
NAME CPU % MEM USAGE / LIMIT MEM % PIDS
practice1-app 0.15% 220.1MiB / 512MiB 42.98% 32
프로토콜별로 연결을 생성하고 GC 전후 JVM 힙/스레드를 측정합니다.
# 전체 프로토콜 순차 테스트 (100개 동시 연결)
curl 'localhost:8080/api/benchmark/all?connections=100' | python3 -m json.tool
# 개별 프로토콜 테스트
curl 'localhost:8080/api/benchmark/http?connections=100' | python3 -m json.tool
curl 'localhost:8080/api/benchmark/sse-emitter?connections=100' | python3 -m json.tool
curl 'localhost:8080/api/benchmark/sse-flux?connections=100' | python3 -m json.tool
curl 'localhost:8080/api/benchmark/websocket?connections=100' | python3 -m json.tool호스트에서 curl로 동시 연결을 생성하고, docker stats와 Actuator로 컨테이너/JVM 수준 메트릭을 동시에 수집합니다.
터미널 1 — docker stats 실시간 모니터링:
docker stats practice1-app터미널 2 — 부하 발생 및 Actuator 측정:
CONNECTIONS=200
# Baseline 측정
curl -s localhost:8080/actuator/metrics/jvm.memory.used | python3 -m json.tool
curl -s localhost:8080/actuator/metrics/jvm.threads.live | python3 -m json.tool
# HTTP 부하 (200개 동시 요청 x 10회)
for round in $(seq 1 10); do
for i in $(seq 1 $CONNECTIONS); do
curl -s localhost:8080/api/hello > /dev/null &
done
wait
done
# → 터미널 1에서 docker stats 변화 확인
# → Actuator 다시 측정
# SSE 부하 (200개 동시 연결 유지)
for i in $(seq 1 $CONNECTIONS); do
perl -e 'alarm 15; exec @ARGV' -- curl -s -N localhost:8080/api/sse/stream > /dev/null &
done
# → 3초 후 docker stats 확인
# → Actuator 측정
# SSE Flux 부하
for i in $(seq 1 $CONNECTIONS); do
perl -e 'alarm 15; exec @ARGV' -- curl -s -N localhost:8080/api/sse/flux > /dev/null &
done
# → 동일하게 측정
# WebSocket (SockJS xhr_streaming) 부하
for i in $(seq 1 $CONNECTIONS); do
SRV=$((RANDOM % 900 + 100))
SID=$(cat /dev/urandom | LC_ALL=C tr -dc 'a-z' | head -c 8)
perl -e 'alarm 15; exec @ARGV' -- curl -s -N "localhost:8080/ws/$SRV/$SID/xhr_streaming" > /dev/null &
done
# → 동일하게 측정각 프로토콜의 헤더 오버헤드를 확인합니다.
# HTTP — 매 요청마다 전체 헤더 교환
curl -v localhost:8080/api/hello
# SSE — 최초 1회 헤더 후 데이터만 스트리밍
perl -e 'alarm 4; exec @ARGV' -- curl -v -N localhost:8080/api/sse/stream
# WebSocket — HTTP 101 업그레이드 핸드셰이크
perl -e 'alarm 3; exec @ARGV' -- curl -v \
-H "Upgrade: websocket" \
-H "Connection: Upgrade" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
-H "Sec-WebSocket-Version: 13" \
localhost:8080/ws/websocketdocker-compose down| 파일 | 설명 |
|---|---|
| benchmark-report.md | 로컬 JVM 내부 측정 결과 (100 연결) |
| benchmark-report-docker.md | Docker 격리 환경 측정 결과 (200 연결, 512MB/1CPU) |