CPU가 100%일 때
CPU 코어를 잡아먹는 프로세스를 찾고, 실제 부하와 디스크 대기를 구분하며, 코드를 수정할지 더 높은 티어로 이동할지 결정하는 방법을 알아봐요.
업데이트 2026년 8월 23일
“개요” 탭의 CPU 그래프에서 나타나는 평탄한 구간은 그 자체로 비상 상황이 아니에요. 프로젝트를 빌드하거나 압축 파일을 만들면 모든 코어를 실제로 사용한 뒤 다시 반환하기 때문이에요. 문제가 되는 건 이 평탄한 구간이 몇 시간씩 이어지면서 머신이 응답을 멈출 때예요. 무엇이 원인인지 알아볼게요.
1단계. 무엇이 리소스를 소비하는지 확인하기
전체 화면 프로그램을 다룰 때는 “화면”(VNC) 탭이 편리해요:
btop
htop
시리얼 콘솔은 창 크기를 전달하지 않아서 항상 80×24로 고정되므로 인터페이스가 잘려요. 텍스트 콘솔에서는 표준 명령어를 사용하세요:
top -b -n1 | head -20
ps aux --sort=-%cpu | head -10
계산 방식을 기억하세요. %CPU는 코어별로 계산돼요. VDS-3에서 400%는 네 개 코어 전부를 뜻하고, VDS-4에서 100%는 여섯 개 중 하나만 쓰는 것일 뿐이에요.
2단계. CPU와 디스크 구분하기
평균 부하(load average)는 연산뿐 아니라 I/O 대기 때문에도 올라가요:
uptime
vmstat 1 5
vmstat 출력에서는 us(사용자 코드), sy(커널), wa(디스크 대기), st(강탈된 시간) 열을 보세요. wa가 크다는 건 CPU가 디스크를 기다리며 놀고 있다는 뜻이에요. 즉 병목은 연산이 아니라 쓰기 속도예요. 저희 티어의 디스크 평탄 구간은 규칙으로 정해져 있어요. 코어당 쓰기 60 MB/s, 최소 60 MB/s에서 최대 400 MB/s이고, 읽기는 그 두 배이며, 평탄 구간의 세 배까지 버스트가 30초 동안 유지돼요. 작업이 계속 쓰기를 하면 버스트가 끝나고 평탄 구간에 부딪히게 돼요.
3단계. 특정 프로세스 조사하기
pidstat -p <pid> 1 5
cat /proc/<pid>/status
journalctl -u <service> -n 100 --no-pager
흔히 발견되는 사례는 다음과 같아요:
- 웹 애플리케이션이 실패한 요청 이후 무한 루프를 도는 경우;
- 데이터베이스가 인덱스 없이 쿼리를 실행하는 경우 — 데이터베이스 자체의 슬로우 쿼리 로그를 확인하세요;
- cron 작업이 끝나기 전에 더 자주 시작되어 인스턴스가 쌓이는 경우:
ps aux | grep <name>으로 열 개가 넘는 사본이 보여요; - 취약한 root 비밀번호를 통해 머신에 들어온 채굴 프로그램. 징후는 의미 없는 이름의 프로세스가 비표준 사용자로 실행되면서 나가는 대역폭이 높은 것이에요. 이 경우에는 정리하는 것보다 “접근” 탭에서 머신을 재설치하는 편이 더 쉬워요.
4단계. 죽이지 말고 제한하기
프로세스가 필요하지만 나머지에 방해가 되면 안 될 때는:
renice -n 15 -p <pid>
systemctl set-property myapp.service CPUQuota=200%
CPUQuota=200%는 코어 두 개 전부예요. systemd 제한은 서비스를 재시작해도 유지되지만 renice는 유지되지 않아요.
kill -9로 프로세스를 죽이기 전에 일반적인systemctl stop을 먼저 시도하세요. 데이터베이스를 강제로 죽이면 파일이 손상되고 다음 시작 시 복구에 오래 걸려요.
코드 문제가 아닐 때
부하가 정당하고 일정하다면 Ryzen 9 7950X CPU는 제 역할을 하고 있는 거예요. 단지 작업에 필요한 코어가 부족할 뿐이에요. 티어는 상향으로만 변경할 수 있고, 결제한 기간의 남은 일수에 대한 추가 결제가 필요해요. 자세한 내용은 요금제 업그레이드와 차액 결제 문서를 참고하세요. 다시 하향하는 것은 불가능하므로, 먼저 주간 및 월간 그래프를 보고 평탄 구간이 일회성인지 확인하세요.