CPU Load Average 해석

2,482 단어·5 분·원문(.md)

CPU Load Average는 시스템의 부하 상태를 나타내는 핵심 지표지만 단순히 cpu 사용률과는 다르다.

Load Average #

리눅스 시스템에서 load average는 실행중이거나 실행 대기 상태에 있는 프로세스(테스크)의 평균 개수를 의미한다.

구체적으로 /proc/loadavg 파일에서 데이터를 가져오며 다음 두 가지 상태의 프로세스 합계를 측정한다

  • R (Runnking / Runnable): cpu를 사용중이거나 사용하기 위해 run queue에서 대기중인 프로세스
  • D (Uninterruptible Sleep): 디스크 io나 네트워크 응답등을 기다리며 대기중인 프로세스, 이 상태는 시그널에 의해 중단되지 않는 상태로 리눅스 특유의 load 계산 방식에 포함된다.

top, uptime, htop 명령어를 실행하면 세 개의 숫자가 출력되는데 이는 각각 최근 1분 5분 15분동안 지수 이동 평균 Exponential Moving Average 값이다.

  • uptime: 시스템 가동 시간과 load average만 간결하게 보여줌
  • top: 시스템 전체 상태와 프로세스 리스트를 보여줌 load average는 최상단 첫번째줄에 나옴
  • htop: 코어별 부하상태와 load average를 직관적으로 보여줌
$ uptime
 14:20:05 up 35 days,  2:45,  3 users,  load average: 4.15, 2.30, 1.05

$ top - 14:22:10 up 35 days,  2:47,  3 users,  load average: 8.50, 5.20, 3.10
Tasks: 250 total,   2 running, 248 sleeping,   0 stopped,   0 zombie
%Cpu(s): 15.0 us,  5.0 sy,  0.0 ni, 10.2 id, 69.8 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  16000 total,   2000 free,   8000 used,   6000 buff/cache
MiB Swap:   4096 total,   4000 free,     96 used.   7500 avail Mem

$ htop
1  [||||||||||           25.0%]   Tasks: 145, 325 thr; 3 running
2  [||||||               15.0%]   Load average: 0.65 0.88 1.12 
3  [||||||||||||||||     45.0%]   Uptime: 10 days, 05:12:30
4  [||                   05.0%]
Mem[|||||||||||||    4.50G/16G]
Swp[|                120M/4.0G]

만약 서버가 4core라면 uptime기준 현재(1분전) 부하율은 103%(4.15/4)이다 15분전에 비해 부하가 급격히 상승하여 현재 시스템이 처리 용량을 약간 초과한 상태

지수 이동 평균을 사용하는 이유는 단순히 산술 평균을 내면 과거의 데이터가 현재 부하상태를 정확히 반영못하므로

최근 데이터에 높은 가중치를 두어 감쇠 decay 시키는 방식을 취한다.

흐름파악을 위해서인데

  • 1분 > 5분 > 15분: 부하가 급장하고있는 상태
  • 1분 < 5분 < 15분: 부하가 정점을 찍고 감소하고 있는 상태
  • 세 수치가 비슷하면 안정적인 유지를 의미

Threshold 판단 기준 #

Load Average 숫자의 절대값만으로는 시스템의 과부화 여부를 판단할 수 없고 반드시 논리적 cpu 코어의 개수와 비교해야한다.

  • Load Average / CPU 코어 수 = 1.0 이라면 해당 코어가 쉬지않고 가동되고 있으며 대기열은 없는 상태
  • 1.0 미만이라면 cpu 자원이 남는 상태고
  • 1.0 초과라면 cpu 자원이 부족해 프로세스들이 런큐에 대기하거나 io 병목으로 인해 지연이 발생하고 있는 상태다

4 Core 시스템에서 Load가 2.0인거면 자원의 50%를 사용중인거고 1Core 시스템에서 2.0이면 1개의 프로세스는 실행중이며 나머지 1개는 대기중인 상태인것이다.

Loand Average vs CPU Utilization #

많은 관리자가 cpu 사용률%하고 Load Average를 혼동하는데 결정적인 차이를 정리해보겠다.

CPU Utilization

  • 측정값은 특정 시간동안 cpu가 연산에 투입된 시간의 비율
  • I/O 대기가 반영이 안되고 io wait시 cpu는 유휴 상태로 간주함
  • 100%가 최댓값이다 코어당

Load Average

  • 측정값은 실행 및 대기중인 프로세스 개수 (수요량)
  • io 대기 반영을 강력하게 하고
  • 최댓값은 제한이 없다 대기열이 길수록 무한이 상승함.

cpu 사용률은 낮은데 load average가 높다면 이는 계산 능력이 부족한게 아니라 디스크 I/O 병목일수있다 이렇게 유추해볼수있겟다.

혹은 네트워크 파일시스템 NFS의 응답지연이라거나 어쨋든 계산 능력이 딸리는건 아님

수학적 계산 원리 #

리눅스 커널은 매 5초마다 현재 실행/대기중인 테스크 수를 카운트한다. 지수 이동 평균 공식은 대략 아래와 같다

Loadnew=Loadold×e5/60+n×(1e5/60)Load_{new} = Load_{old} \times e^{-5/60} + n \times (1 - e^{-5/60})

n = 현재 측정된 실행/대기 테스크 수, e는 자연상수다

이 공식을 통해 잛은 순간의 스파이크 부하가 전체 평균을 왜국하는것을 방지하면서도 지속적인 부하 추세를 반영한다.

코어수 확인은 grep -c ^processor /proc/cpuinfo 뭐 이런걸로 할수잇고

현재 load average 상태가 이상하다면 15분 평균 먼저 확인해서 일시적인 현상인지 구좆거 문조인지 판단하자.

D 상태 추적을 하는것도 즉 load는 높은데 cpu가 낮다면 ps -aux로 명령어 프로세스 상태가 D(대기중인) 것들이 많은지 확인하고 스토리지나 네트워크 io부분을 점검하도록 하자.


Load Average & CPU가 다 사용률이 높을때 #

이 뜻은 cpu 연산 자원 자체가 부족해서 프로세스들이 실행을 위해 대기하고 있는 cpu bound 상태이다.

이럴땐 먼저 범인 프로세스를 식별해야하고 top, htop로 찾고 P키를 눌러 cpu 사용량 순으로 정렬후 PID USER %CPU COMMAND 열을 확인후

특정 프로세스가 독점하고 있는지 여러 프로세스가 골고루 점유하는지 먼저 파악하자

ps -eo pid,ppid,cmd,%cpu --sort=-%cpu | head -n 10

그 이후 부하 성격을 분석하자 CPU State Classification

top의 상단 cpu% 행을 분석해 문제의 원인을 좁히자.

  • %us 는 사용자 모드 애플리케이션 연산량이고 이게 높으면 애플리케이션 로직 문제, 무한루프라던가 과도한 연산 코드 최적화가 필요하다
  • %sy 는 커널 모드 작업 sw 인터럽트등의 연산량이고 이게 높으면 과도한 시스템 콜 컨텍스트 스위칭, 네트워크 스택 부하등이 이유다
  • %ni 는 우선순위가 낮게 설정된 작업 백그라운드 작업 백업, 인덱싱등이 자원을 쓰는중이고 우선순위 조정이 필요하다.
  • %si 는 소프트웨어 인터럽트 처리로 네트워크 패킷 처리가 너무 많거나 드라이버가 문제다.

심층 진단 #

프로세스를 찾아냈다면 그 내부에 무슨일이 벌어지는지도 확인해야한다.

멀티 스레드 확인은 top -H -p PID로 특정 프로세스 내의 어던 스레드가 cpu를 쓰는지 확인한다.

strace -p PID -c를 통해서 시스템 콜을 추적해 프로세스가 어떤 시스템 콜을 과도하게 호출하는지 pidstat -u 1로 특정 간격으로 프로세스별 cpu 사용 추이를 모니터링한다.

vmstat 1로 context switching (cs) 수치가 초당 수만건 이상으로 높은지 확인하고 cpu가 실제 연산보다 프로세스간 전환작업을 많이 낭비하고있는지 체크하자

renice -n 19 -p 1234 이런걸로 1234 프로세스의 우선순위를 19(최하)로 낮춰 일단 응급조치를 해도되고 kill은 ... 할수있으면 해도 되고

혹은 cpulimit -p [PID] -l 50으로 사용량을 강제할수도있다.

  1. 근본적으로는 cpu affinity 설정으로 특정 프로세스는 특정 코어에 taskset하여 캐시효율을 높이고 컨텍스트 스위칭을 줄여본다거나.
  2. Cgroups 설정으로 시스템 차원에서 서비스별 사용할 수 있는 자원 상한선을 지정 (이건 k8s환경이면 더 쉬울거임)
  3. 스케일 업 아웃등으로 하는게 가장 쉬운 해결법이긴하다 ㅋㅋ 애플리케이션 코드 최적화도 최대한 해보고 ㅇㅇ
  • top으로 범인 PID를 찾는다.
  • %us가 높으면 어플리케이션 코드/로직을 의심한다.
  • %sy가 높으면 시스템 콜이나 컨텍스트 스위칭을 의심한다.
  • 급하다면 renice로 우선순위를 낮추거나 kill로 종료한다.
SRE/question/q_18.md