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
지표해석
vmstatr(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 환경에서 기본 제공. 오래된 커널이면 vmstatr 컬럼이나 코어별 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)

답글 남기기