Search
🚀

데벨업 — 우아한테크코스 팀 프로젝트

개요

항목
내용
기간
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
    end
Mermaid
복사
모니터링 스택:
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 --> D
Mermaid
복사
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 --> H
Mermaid
복사

배운 점

단일 EC2에서 시작해 모니터링 추가 → 분산 인프라 → 무중단 배포까지, 각 단계의 필요성을 실제로 체감한 뒤에 도입하는 것이 효과적이었음
SSH 차단 환경에서 Self-Hosted Runner를 도입하거나, 예산 제약으로 Blue-Green 대신 Rolling을 선택하는 등 제약 조건 내에서 최적의 결정을 내리는 경험