CPU 사용률이 거짓말하는 이유 — Utilization vs Saturation

모니터링 대시보드의 CPU 사용률이 20~30%인데 애플리케이션 응답은 계속 느려지는 상황을 겪어본 적이 있을 것이다. 흔히 보는 시스템 전체 평균 %CPU는 여러 코어를 뭉뚱그린 값이라, 일부 코어만 100% 포화된 상태를 “아직 여유 있음”으로 왜곡해서 보여줄 수 있다. 사용률(utilization)과 포화도(saturation)는 다른 지표인데 하나로 뭉쳐 보면 이 차이가 감쪽같이 사라진다. 이 글에서는 일부러 코어 일부만 포화시켜 이 왜곡을 재현하고, PSI로 진짜 포화 여부를 확인하는 법을 정리한다.

Utilization과 Saturation

지표의미흔한 함정
Utilization(사용률)리소스가 바쁜 시간의 비율여러 코어를 평균 내면 일부 코어의 100%가 희석된다
Saturation(포화도)리소스를 기다리는 작업이 쌓여 있는 정도(큐 길이)사용률만 보면 이 대기열 자체가 안 보인다

재현 — 코어 절반만 포화시키기

6코어 중 3개(0~2번)에만 무한 루프 프로세스 12개를 taskset -c 0-2로 몰아넣고 mpstat을 확인했다.

$ mpstat -P ALL 1
Average:     CPU    %usr  ...  %idle
Average:     all   13.50  ...  85.93   ← 전체 평균만 보면 한가해 보임
Average:       0   98.08  ...   0.00
Average:       1  100.00  ...   0.00
Average:       2  100.00  ...   0.00
Average:       3    0.00  ...  100.00
Average:       4    0.00  ...  100.00
Average:       5    0.00  ...   98.69

all 행만 보면 13.5%로 여유가 넘쳐 보이지만, 코어별로 쪼개보면 0~2번은 완전 포화(98~100%)고 3~5번만 놀고 있다. 대시보드가 시스템 전체 평균만 보여준다면 이 포화 상태는 완전히 감춰진다.

run queue와 PSI로 포화도 직접 확인

$ vmstat 1
procs -----------memory---------- ---system-- -------cpu-------
 r  b   swpd   free   buff  cache   in   cs us sy id wa
13  1  13400 6576300 10876 914172  619    0  0  1 97  2
14  0  13400 6576608 10876 914220  751  410 14  0 84  2
12  0  13400 6577520 10876 914220  982  496 17  1 82  0

$ cat /proc/pressure/cpu
some avg10=53.64 avg60=14.49 avg300=20.31 total=486129702

$ uptime
load average: 1.08, 0.59, 0.46
지표값해석
vmstat의 r(run queue)12~14동시에 실행 가능한(runnable) 프로세스 수. 코어 3개로는 이 중 3개만 동시에 처리 가능
PSI cpu some avg1053.64%최근 10초 동안 최소 1개 태스크가 CPU를 못 받아 대기한 시간의 비율. 시스템 평균 사용률 13.5%와 정반대 신호

run queue 12~14는 코어 3개가 감당할 수 있는 수(최대 3)를 크게 웃돌고, PSI는 절반 넘는 시간 동안 뭔가가 CPU를 기다렸다고 정확히 알려준다. 사용률(13.5%)과 포화도(53.64%)가 이렇게 반대로 갈 수 있다는 게 이 글의 핵심이다.

대조 — 코어 수만큼만 배치한 정상 케이스

같은 실험을 프로세스 12개 대신 6개로, 코어 6개에 1:1로 배치해서 반복했다.

$ mpstat -P ALL 1
Average:     all   85.71 ...  %idle  0.00
$ cat /proc/pressure/cpu
some avg10=24.54 avg60=22.44 avg300=11.50

이번엔 all 사용률(85.71%)이 실제 부하를 정직하게 반영한다 — 코어마다 프로세스 하나씩이라 평균이 왜곡될 여지가 없다. PSI도 24.54%로, 앞선 12:3 케이스(53.64%)의 절반 이하로 떨어졌다. 사용률이 커져도 코어 수와 실행 가능한 작업 수가 맞아떨어지면 포화도는 오히려 낮아진다는 걸 확인할 수 있다.

주의사항

항목내용
PSI는 비교적 최근 기능커널 4.20 이상, cgroup v2 환경에서 기본 제공. 오래된 커널이면 vmstat의 r 컬럼이나 코어별 mpstat으로 대체
full vs some 구분some은 하나라도 대기 중이면 카운트, full은 모든 실행 가능 태스크가 동시에 막혀 CPU가 완전히 낭비된 시간만 카운트. 둘 다 확인할 것
평균 사용률 대시보드만 믿지 말 것알림 임계값을 시스템 전체 평균 %CPU로만 걸어두면 이런 국소 포화를 놓친다. 코어별 최댓값이나 PSI 기반 알림을 병행할 것
taskset/cpuset 오배치가 원인일 수 있다이번 재현처럼 특정 코어에 프로세스가 몰리는 원인은 애플리케이션 설계보다 CPU affinity 설정 실수인 경우도 많다

마무리

시스템 전체 평균 사용률이 낮다고 여유가 있다고 단정하지 말 것. 코어별 mpstat, run queue 길이, 그리고 가능하면 PSI까지 함께 봐야 진짜 포화 상태인지 판단할 수 있다. USE 메소드(Utilization, Saturation, Errors)의 세 지표를 함께 보는 습관이 여기서 나온다.

참고

Brendan Gregg – USE Method: Linux Performance Checklist
Kernel.org – Pressure Stall Information (PSI)

답글 남기기