배경
Feel-Archive 프로젝트 성능 측정을 진행하기 전에 서버 자원 지표를 수집하기 위해 Prometheus 도입을 결정했다. Grafana까지 EC2에 올리면 메모리 부담이 크다고 판단해 Prometheus만 docker-compose에 추가했다. Spring Boot Actuator를 사용하였고Prometheus가 15초마다 수집하는 구조였다.
원인 & 문제 해결
처음에 기존에 EC2에 Spring App, MySQL, Redis가 띄워져있는 상태로 Prometheus도 추가해줬는데 터미널이 아예 먹통이 되어서 메모리나 docker stats같은것도 확인할 수 없어서 재부팅 후 Spring App에 메모리를 할당해주고 재시작했다.
그제서야 이제 터미널 먹통이 조금 풀리고 명령어를 실행할 수 있어서 확인해봤는데 free -h로 확인해보니, 가용 메모리가 25MB밖에 없었다.
total used free shared buff/cache available
Mem: 957Mi 819Mi 76Mi 1.0Mi 60Mi 25Mi
Swap: 0B 0B 0B
docker stats로 도커 상태를 확인했는데 다음과 같았다.
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
84a29d196a49 feel-archive 0.15% 311.2MiB / 350MiB 88.91% 35.4kB / 28.8kB 170MB / 176kB 35
6e133272f809 feel-mysql 0.37% 201.1MiB / 350MiB 57.45% 100kB / 115kB 319MB / 18MB 44
d02cb7bc5de5 feel-redis 0.21% 5.113MiB / 50MiB 10.23% 2.14kB / 126B 51.7MB / 0B 6
기존 시스템은 Spring Boot 350MB, DB 350MB, Redis 50MB로 컨테이너별 mem_limit을 설정해 운영 중이었다. docker stats 지표를 확인한 결과, DB의 실제 메모리 사용량은 할당량의 57% 수준이었다. 성능 측정을 위한 Prometheus 컨테이너(최소 50MB 필요)를 실행하기 위해, 여유가 확인된 DB의 mem_limit을 350MB에서 250MB로 하향 조정했다. 이를 통해 각 컨테이너의 메모리 상한선 총합이 서버의 물리적 가용 메모리를 초과하지 않도록 제어하고, Prometheus가 안전하게 동작할 수 있는 공간을 시스템 차원에서 보장했다.
운영 환경의 mem_limit의 기준은 로컬 환경에서 docker stats해서 나온 값의 * 2배 정도를 줬다. 이유는 운영 환경은 트래픽이 있어 로컬보다 메모리 사용량이 높을 수 있고, OOM으로 컨테이너가 강제 종료되는 것을 방지하기 위해 여유분을 두고 2배로 설정했다.
prometheus를 띄우는데 성공은 했지만 가용 메모리를 확인해보니 여전히 적어서 터미널이 먹통이 되었다.
total used free shared buff/cache available
Mem: 957Mi 839Mi 62Mi 1.0Mi 54Mi 9.0Mi
Swap: 0B 0B 0B
컨테이너별 자원 할당량을 이미 최적화된 최소 수준으로 조정해서 더 이상 조정할 부분이 없어서 SWAP 메모리를 사용하도록 결정했다.
Filesystem Size Used Avail Use% Mounted on
/dev/root 7.6G 5.8G 1.8G 77% /
tmpfs 479M 0 479M 0% /dev/shm
tmpfs 192M 1.2M 191M 1% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
/dev/xvda15 105M 6.1M 99M 6% /boot/efi
tmpfs 96M 4.0K 96M 1% /run/user/1000
현재 1.8GB 정도 여유분이 있어서 1GB 정도 SWAP 메모리로 설정했다.
프로메테우스 띄우기 전, SWAP 메모리 확인
total used free shared buff/cache available
Mem: 957Mi 742Mi 66Mi 0.0Ki 148Mi 61Mi
Swap: 1.0Gi 38Mi 985Mi
프로메테우스 띄운 후, 메모리 및 docker stats 확인
total used free shared buff/cache available
Mem: 957Mi 546Mi 65Mi 0.0Ki 345Mi 256Mi
Swap: 1.0Gi 334Mi 689Mi
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
6065b04f0362 feel-mysql 0.42% 193.4MiB / 250MiB 77.35% 20.9kB / 20.1kB 87.5MB / 16.8MB 45
84a29d196a49 feel-archive 0.11% 201.7MiB / 350MiB 57.64% 1.12MB / 14MB 316MB / 313MB 37
e1914603de1b feel-prometheus 0.02% 16.23MiB / 50MiB 32.45% 13.3MB / 2.46MB 244MB / 32.7MB 7
d02cb7bc5de5 feel-redis 0.14% 1.367MiB / 50MiB 2.73% 16.7kB / 2.75kB 37.9MB / 4.21MB 6
Prometheus 실행 후 OS가 당장 사용하지 않는 메모리 페이지를 Swap 영역으로 이동시키면서 물리 메모리 가용 공간을 256MB만큼 확보할 수 있었다.
느낀점
실제 운영 환경에서 t2.micro와 같은 스펙을 사용하는 경우는 드물다. 서버 스펙업으로 간단히 해결할 수 있지만, 그 전에 현재 자원에서 최적화할 수 있는 부분이 있는지 확인하는 것이 먼저라고 생각했다. docker stats, free -h같이 아주 기본적인 명령어로 실제 사용량을 측정하고 수치 기반으로 메모리를 조정하는 경험을 할 수 있었다.
'Feel-Archive' 카테고리의 다른 글
| [Feel-Archive] 스케줄러 블로킹을 해결하기 위한 비동기 처리 - 타임캡슐 알림 개발 (1) (0) | 2026.03.18 |
|---|---|
| [Feel-Archive] N+1 감지 시스템 구축기 (0) | 2026.03.12 |
| [Feel-Archive] 타임캡슐 알림이 9시간 늦게 온다 (0) | 2026.03.08 |