Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- insertion sort
- 이것이 자바다
- Algorithm
- 혼자 공부하는 C언어
- JSON
- coding test
- 윤성우의 열혈 자료구조
- C programming
- 알기쉬운 알고리즘
- Serialization
- stream
- C 언어 코딩 도장
- 메모리구조
- 이스케이프 문자
- s
- list 컬렉션
- Selection Sorting
- Stack
- 윤성우 열혈자료구조
- datastructure
- buffer
- Graph
- R
Archives
- Today
- Total
Engineering Note
[SW Engineering] Spring Boot 배포 최적화 본문
메모리 문제 해결 및 자동화 구축 보고서
개요
환경 정보
- 플랫폼: Google Cloud Platform 프리티어
- 서버 스펙: vCPU 2개, RAM 1GB, 디스크 30GB
- 애플리케이션: Spring Boot + MySQL
초기 문제 상황
수동 배포 과정에서 서버 메모리 부족으로 인한 빌드 실패 및 성능 저하 발생
문제 분석
1. 메모리 사용량 실측 데이터
서버 메모리 현황 분석
# 실제 측정 결과 (top 명령어 출력)
mysqld: 249MB (26.0% 사용)
기타 시스템 프로세스: 262MB
총 사용량: 511MB
가용 메모리 계산
VM 총 메모리: 958MB (1GB 중 실제 사용 가능)
시스템 기본 사용량: 511MB
실제 가용 메모리: 447MB
2. Maven 빌드 메모리 요구량 측정
스왑 메모리 사용량 분석
# 빌드 중 스왑 사용량 (swapon -s 결과)
총 스왑: 1,024MB
사용량: 278MB (27.1%)
Maven 빌드 실제 메모리 소비
가용 메모리: 447MB
빌드 필요량: 278MB (스왑 사용량으로 측정)
이론상 여유: 169MB
3. 성능 저하 원인 분석
메모리 압박 상황
- 가용률: 447MB ÷ 958MB = 46.7%
- 빌드 요구율: 278MB ÷ 447MB = 62.2%
- 총 사용률: (511MB + 278MB) ÷ 958MB = 82.3%
실제 발생한 문제
- OutOfMemory 오류: 발생하지 않음
- 실제 증상: 빌드 프로세스 무응답 및 시스템 전체 응답 지연
- 원인: 메모리 압박으로 인한 스래싱(Thrashing) 현상
해결 방안 및 구현
1. 스왑 메모리 추가
구현 내용
sudo fallocate -l 1G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
스왑 크기 결정 근거
고려사항 수치 근거
최소 필요량 | 278MB | 실측된 빌드 메모리 요구량 |
안전 마진 | 300MB | 시스템 안정성 확보 |
디스크 사용률 | 3.3% | 30GB 중 1GB 사용 (적정 수준) |
성능 고려 | 1GB | 과도한 스왑 사용 방지 |
효과 검증
빌드 전 가용 메모리: 447MB
스왑 추가 후 총 가용: 1,471MB (447MB + 1,024MB)
메모리 압박 해소: 82.3% → 53.6%
2. GitHub Actions 자동화 구축
기존 수동 배포 프로세스
1. 서버 SSH 접속 (30초)
2. Git pull (1분)
3. Maven 빌드 (3분, 메모리 부족으로 지연)
4. 애플리케이션 재시작 (30초)
총 소요시간: 5분
자동화 배포 프로세스
# GitHub Actions Workflow
1. 코드 체크아웃 (10초)
2. JDK 17 설정 (10초)
3. Maven 빌드 (GitHub 서버, 30초)
4. JAR 파일 서버 전송 (20초)
5. 애플리케이션 재시작 (10초)
총 소요시간: 1분 20초
핵심 개선사항
- 빌드 환경 분리: GitHub 고성능 서버에서 빌드 수행
- 서버 부하 경감: 실행만 담당하여 메모리 사용량 최소화
- 자동화: git push 트리거로 전체 과정 자동 실행
성능 개선 결과
1. 배포 시간 개선
구분 수동 배포 자동 배포 개선율
총 소요시간 | 5분 | 1분 20초 | 73.3% 단축 |
사람 개입시간 | 5분 | 0분 | 100% 자동화 |
빌드 실패율 | 높음 | 0% | 안정성 확보 |
2. 시스템 리소스 최적화
항목 개선 전 개선 후 효과
서버 메모리 압박 | 82.3% | 53.6% | 압박 해소 |
빌드 성공률 | 불안정 | 100% | 안정성 확보 |
서버 다운타임 | 빈번 | 없음 | 서비스 안정성 |
3. 메모리 사용 패턴 개선
개선 전: 물리 메모리만 사용 → 빌드 실패/지연
개선 후: 물리 메모리 + 스왑 → 안정적 실행
실측 데이터:
- 빌드 시 스왑 사용: 278MB
- 빌드 완료 시간: 24.488초 (안정적)
- 시스템 무응답: 해결
기술적 구현 세부사항
1. 메모리 모니터링 시스템
# 실시간 메모리 사용량 추적
while true; do
timestamp=$(date '+%H:%M:%S')
used_mem=$(free -m | grep Mem | awk '{print $3}')
available_mem=$(free -m | grep Mem | awk '{print $7}')
swap_used=$(free -m | grep Swap | awk '{print $3}')
echo "$timestamp - Used: ${used_mem}MB Available: ${available_mem}MB Swap: ${swap_used}MB"
sleep 2
done
2. GitHub Actions 최적화 설정
# 메모리 제한된 환경에서의 JVM 최적화
script: |
nohup java -Xmx400m -Xms200m -jar shop-0.0.1-SNAPSHOT.jar > app.log 2>&1 &
3. 성능 모니터링 지표
- 빌드 성공률: 100%
- 평균 배포 시간: 1분 20초
- 서버 안정성: 무응답 현상 해결
- 메모리 사용 효율성: 스래싱 현상 제거
핵심 성과 및 교훈
1. 문제 해결 접근법
- 데이터 기반 분석: 실제 메모리 사용량 측정을 통한 정확한 문제 진단
- 근본 원인 해결: 임시방편이 아닌 구조적 개선
- 단계별 검증: 각 해결책의 효과를 개별적으로 검증
2. 리소스 최적화 전략
- 하이브리드 메모리 전략: 물리 메모리 + 스왑 메모리 조합 활용
- 작업 분산: 리소스 집약적 작업을 외부 환경으로 분리
- 자동화를 통한 효율성: 인적 리소스 절약 및 일관성 확보
3. 확장 가능성
- 무중단 배포 기반 마련: Blue-Green 배포 도입 가능
- 모니터링 시스템 구축: 성능 지표 지속 추적 체계
- 클라우드 네이티브 전환: Docker, Kubernetes 도입 기반
ROI (투자 대비 효과) 분석
투자 비용
- 초기 설정 시간: 4시간
- 학습 비용: GitHub Actions, 스왑 메모리 개념 학습
- 추가 리소스: 1GB 디스크 공간 (월 $0.04)
절약 효과
- 배포 시간 단축: 배포당 3분 40초 절약
- 배포 빈도: 주 2회 × 월 4주 = 월 8회
- 월간 시간 절약: 29분 20초
- 연간 효과: 352분 (약 6시간)
정성적 효과
- 배포 스트레스 제거: 실패 위험 없는 안정적 배포
- 개발 집중도 향상: 배포 작업에서 해방
- 서비스 안정성: 서버 다운타임 제거
결론 및 향후 계획
이 프로젝트를 통해 제한된 리소스 환경에서도 체계적인 분석과 최적화를 통해 상당한 성능 개선을 달성할 수 있음을 입증했습니다. 특히 실제 데이터 측정을 바탕으로 한 문제 진단과 해결책 검증이 핵심 성공 요인이었습니다.
향후 개선 방향
- 모니터링 자동화: 메모리 사용량 알림 시스템 구축
- 성능 최적화: 애플리케이션 레벨 메모리 사용량 최적화
- 인프라 업그레이드: 비용 대비 효과 분석 후 메모리 증설 검토
이번 경험은 클라우드 환경에서의 리소스 최적화와 DevOps 자동화 구축에 대한 실질적인 노하우를 제공하며, 향후 유사한 프로젝트의 기반이 될 것입니다.
사용할 리눅스 명령어 정리
top 명령어
실시간 프로세스 모니터링
top -o %MEM # 메모리 사용량 순으로 정렬
제공 정보:
- PID: 프로세스 ID
- %CPU: CPU 사용률
- %MEM: 메모리 사용률
- RES: 실제 물리 메모리 사용량 (KB)
- VIRT: 가상 메모리 사용량
- 실시간 업데이트: 2-3초마다 자동 갱신
우리 프로젝트에서의 활용: MySQL이 249MB(26%) 사용 중인 것을 확인하여 시스템 기본 부하 측정
free 명령어
전체 시스템 메모리 현황
free -h # 사람이 읽기 쉬운 단위로 표시
제공 정보:
- total: 총 메모리 (958MB)
- used: 사용 중 메모리 (511MB)
- free: 완전히 비어있는 메모리
- available: 실제 사용 가능한 메모리 (447MB)
- swap: 스왑 메모리 사용량
우리 프로젝트에서의 활용: 빌드 전후 메모리 사용량 변화 추적, 스왑 사용량 278MB 측정
ps aux 명령어
모든 프로세스의 상세 정보
ps aux --sort=-%mem # 메모리 사용량 내림차순 정렬
제공 정보:
- USER: 프로세스 소유자
- %CPU: CPU 사용률
- %MEM: 메모리 사용률
- RSS: 실제 메모리 사용량 (KB)
- COMMAND: 실행 명령어
우리 프로젝트에서의 활용: Maven/Java 프로세스 실행 여부 확인, 개별 프로세스별 메모리 소비량 분석
실제 측정에서의 역할
문제 진단 과정:
- free -h: 전체 메모리 상황 파악 (447MB 가용)
- top: 주요 메모리 소비자 식별 (MySQL 249MB)
- ps aux: Maven 빌드 프로세스 추적 및 실패 확인
스크립트 를 통한 메모리 분석 :
실시간 메모리 추적 실행 스크립트
# 실시간 메모리 사용량 추적
while true; do
timestamp=$(date '+%H:%M:%S')
used_mem=$(free -m | grep Mem | awk '{print $3}')
available_mem=$(free -m | grep Mem | awk '{print $7}')
swap_used=$(free -m | grep Swap | awk '{print $3}')
echo "$timestamp - Used: ${used_mem}MB Available: ${available_mem}MB Swap: ${swap_used}MB"
sleep 2
done
1. 무한 루프 구조
while true; do
# 반복 실행
done
2. 데이터 수집 과정
timestamp=$(date '+%H:%M:%S') # 현재 시간 기록
used_mem=$(free -m | grep Mem | awk '{print $3}') # 사용 중 메모리
available_mem=$(free -m | grep Mem | awk '{print $7}') # 가용 메모리
swap_used=$(free -m | grep Swap | awk '{print $3}') # 스왑 사용량
3. 출력 형식
04:31:27 - Used: 583MB Available: 374MB Swap: 0MB
04:31:29 - Used: 583MB Available: 374MB Swap: 0MB
4. 2초 간격 측정
sleep 2 # 2초 대기 후 다시 측정
프로젝트에서의 활용 목적:
Maven 빌드 중 메모리 사용 패턴 추적
- 빌드 시작 전: 기준선 측정
- 빌드 진행 중: 메모리 사용량 변화 관찰
- 스왑 사용량: 실제 메모리 부족량 측정
핵심 측정 데이터:
- Used: 511MB → 물리 메모리 사용량
- Swap: 278MB → 추가로 필요했던 메모리량
이 스크립트로 "Maven 빌드가 278MB 추가 메모리를 필요로 한다"는 정량적 근거를 확보할 수 있었습니다.
'SW Engineering' 카테고리의 다른 글
[SW Engineering] JPQL에서 FETCH JOIN과 DTO 생성자 패턴 충돌 해결하기 (0) | 2025.09.23 |
---|---|
[SW Engineering] JPQL join, fetch join (0) | 2025.09.23 |
[SW Engineering] 동시성 문제 테스트 환경 구축기 (0) | 2025.09.09 |
[SW Engineering] 페이지네이션 성능 측정 최적화(Offset vs Cursor Pagination 성능 비교 (평균 17배 개선)) (0) | 2025.09.08 |
[SW Engineering] 비동기 통신 직접 만들면서 익히기 (0) | 2025.07.21 |
Comments