개요
항목 | 내용 |
기간 | 2024.06 ~ 2024.11 |
역할 | 백엔드 개발 (4인 팀) |
기술 스택 | Java, Spring Boot, Spring Data JPA, MySQL, Docker, AWS (EC2, ALB, RDS), GitHub Actions |
GitHub | |
블로그 | |
서비스 | 개발자 취준생을 위한 풀이 공유 커뮤니티 플랫폼 |
배경
우아한테크코스 6기 팀 프로젝트로, 개발자 취준생들이 코딩 테스트 및 미션 풀이를 공유하고 서로 피드백을 주고받는 플랫폼을 기획하고 개발했습니다.
성능 최적화 — 풀이 목록 조회 3배 개선
문제
•
서비스의 메인 진입점인 풀이 목록 조회 API가 10만 건 데이터 처리에 700ms 소요
•
서비스의 진입점이기 때문에 부하 테스트 대상으로 선정
행동
flowchart LR
A[700ms] -->|쿼리 분할| B[300ms]
B -->|인덱스 추가<br>제출 일자| C[200ms]
C -->|읽기/쓰기 분리<br>라우팅 수정| D[TPS 60→120]Mermaid
복사
1단계: 쿼리 분할 (700ms → 300ms)
•
한 번에 모든 데이터를 가져오는 쿼리를, PK만 먼저 조회한 뒤 해당 PK로 다시 조회하는 방식으로 분할하여 응답 시간 단축
2단계: 인덱스 추가 (300ms → 200ms)
•
제출 일자에 대한 풀이 목록은 제출 일자 기준 정렬이 필요
•
제출 일자에 인덱스를 추가하여 응답 시간 추가 단축
3단계: 읽기/쓰기 분리 (TPS 60 → 120)
•
부하 테스트 시 읽기 데이터베이스 CPU 사용률이 90% 이상, 쓰기 데이터베이스는 30% 수준인 불균형 확인
•
읽기 요청의 일부를 쓰기 데이터베이스에서도 하도록 라우팅 알고리즘 수정
•
TPS 60에서 120으로 2배 개선
결과
지표 | 개선 전 | 개선 후 | 개선율 |
응답 시간 | 700ms | 200ms | 3.5배 |
TPS | 60 | 120 | 2배 |
인프라 — 3단계 점진적 개선
1단계: 초기 (단일 EC2)
flowchart TD
A[Internet] --> B[EC2]
B --> C[Nginx<br>80/443 → 8080]
C --> D[Spring Boot]
D --> E[MySQL]Mermaid
복사
•
하나의 EC2 인스턴스에 Nginx와 Spring Boot를 직접 설치하여 운영
2단계: 모니터링 & 로깅 시스템 구축
베타 테스트 과정에서 오류를 기록하고 추적하는 시스템이 없어 빠른 대응이 힘든 문제를 발견했습니다. 이를 해결하기 위해 모니터링 및 로깅 시스템을 별도 EC2에 구축했습니다.
flowchart TD
subgraph WAS EC2
A[Nginx] --> B[Spring Boot]
B -->|Actuator 8082| D
B -->|Loki4j Appender| F
end
subgraph Monitoring EC2
D[Prometheus] --> E[Grafana]
F[Loki] --> E
endMermaid
복사
모니터링 스택:
•
Spring Boot Actuator + Micrometer — JVM 메모리, CPU, 커넥션/스레드 풀, API별 호출 횟수/응답 시간 메트릭 제공
•
Prometheus — Actuator의 /prometheus 엔드포인트를 주기적으로 수집
•
Loki + Loki4j — Spring Boot 로그를 Loki에 직접 전송 (Logback Appender 방식)
•
Grafana — 메트릭과 로그를 시각화하는 대시보드
설계 결정:
•
모니터링 서버를 WAS와 분리하여 안정성 확보 — 같은 서브넷에 속하도록 하여 내부 통신
•
Actuator 엔드포인트를 8082 포트로 분리하여 외부 접근 차단 (같은 서브넷 내에서만 접근 가능)
•
Docker Compose로 Prometheus, Grafana, Loki를 관리하여 재시작 및 확장 용이
3단계: 분산 인프라 + 무중단 배포
서비스 런칭을 앞두고 WAS나 DB에 문제가 발생해도 서비스를 유지할 수 있도록 분산 인프라를 구축했습니다.
flowchart TD
A[Internet] --> B[ALB]
B -->|HTTPS| C[EC2 A<br>Spring Boot]
B -->|HTTPS| D[EC2 B<br>Spring Boot]
C --> E[RDS Primary]
D --> E
E --> F[RDS Replica]
G[Monitoring EC2<br>Prometheus + Grafana + Loki] --> C
G --> DMermaid
복사
ALB (Application Load Balancer):
•
HTTP → HTTPS 리다이렉트 Rule 설정
•
Target Group에 두 대의 EC2 인스턴스 등록
•
Health Check API(/health)를 구현하여 ALB가 인스턴스 상태를 확인
DB 다중화:
•
RDS Primary/Replica 구성
•
읽기/쓰기 분리 라우팅으로 부하 분산
CI/CD — GitHub Actions + Self-Hosted Runner:
•
우테코 환경에서 SSH 접속이 차단되어 있어 GitHub Actions에서 EC2로 직접 배포 불가
•
Self-Hosted Runner를 EC2에 설치하여 해결 — Runner가 EC2에서 GitHub 측으로 아웃바운드 연결하는 방식
무중단 배포 — Rolling 방식 선택:
검토한 방식 | 판단 |
Canary | A/B 테스트 계획이 없어 이점 없음 |
Blue-Green | EC2 2배 필요하나 예산 제약 |
Rolling | 하위 호환성을 유지하면 트래픽 일괄 전환도 불필요, 채택 |
배포 과정에서 발생할 수 있는 이상현상을 고려한 CD 파이프라인 설계:
flowchart LR
A[롤백에 사용할<br>버전 확인] --> B[빌드]
B --> C[A 서버 배포]
C --> D{A 서버<br>Health Check}
D -->|성공| E[B 서버 배포]
D -->|실패| F[A 서버 롤백]
E --> G{B 서버<br>Health Check}
G -->|성공| H[결과 알림]
F --> I[A 서버<br>Health Check]
I --> HMermaid
복사
배운 점
•
단일 EC2에서 시작해 모니터링 추가 → 분산 인프라 → 무중단 배포까지, 각 단계의 필요성을 실제로 체감한 뒤에 도입하는 것이 효과적이었음
•
SSH 차단 환경에서 Self-Hosted Runner를 도입하거나, 예산 제약으로 Blue-Green 대신 Rolling을 선택하는 등 제약 조건 내에서 최적의 결정을 내리는 경험