brunch

You can make anything
by writing

C.S.Lewis

by doz Nov 16. 2020

1. Load Average에 관해서

Load Average가 무엇인지, 어떻게 알아볼 수 있는지를 확인해보자



출처: scoutapp


Load Average란 프로세스의 여러 상태 중 R 또는 D 상태에 있는 프로세스들의 개수를 1분, 5분, 15분 단위로 평균값을 나타낸 값이다. 부하 값이 일정량 높은 수준에서, 1분 동안의 값이 15분 값에 비해서 작다면 이는 장애가 발생한 지 좀 된 것이며, 15분 값에 비해 1분, 5분의 값이 높다면 점점 더 부하가 심해지고 있는 것이다. 그렇다면 Load Average가 높다는 뜻은 무엇일까?


Load Average가 높다는 것은 많은 프로세스가 현재 실행 중이거나, 네트워크
또는 디스크 작업을 처리하기 위한 대기상태에 있다는 것이다


그렇다면 과연 CPU 코어가 4개짜리와 1개짜리를 사용하는 환경에서 Load Average가 8이라고 한다면 둘 다 동일한 Load Average를 갖고 있는 걸까?

정답은 '아니다'이다. Load Average는 코어의 값에 따라 상대적이다. 코어 4개에서의 Load Average 8은 코어 4개가 각각 동시에 동작하므로 2에 가까우며, 코어 1개에서의 Load Average 8은 한 번에 하나만 실행하게 되므로 8을 나타낸다고 볼 수 있다.


참고로 코어 개수는 cat /proc/cpuinfo 혹은 dmidecode -t processor, lscpu 명령어로 확인 가능하다.

그렇다면 좀 더 이해하기 쉽게 프로세스의 상태들을 알아보자.


R : Running 상태로써 프로세스가 실제로 CPU 자원을 소모하고 있는 실행 중인 상태이다. R이 많다는 것은 CPU 리소스 측면에서 부하가 있다는 것으로 판단할 수 있다.


D : Uninterruptible Sleep 상태로써 인터럽트에 의해서 상태가 변경되지 않는 대기 상태이다. 즉, 현재 대기의 대상이 끝날 때 까지 방해받지 않고 대기한다. 보통 디스크 또는 네트워크 등 I/O 작업 처리를 대기 중인 프로세스의 상태를 말한다.

프로세스가 디스크 읽기 또는 쓰기 작업을 하거나 네트워크 작업을 하게 될 경우, 디스크 디바이스나 네트워크 디바이스에게 요청(~좀 해줄래)을 보내게 된다. 이렇게 되면 프로세스 입장에서 요청에 대한 응답이 올 때까지 아무것도 할 수 없기 때문에 Wait Queue로 들어가며, 자신을 uninterruptible 상태로 마킹한다.

해당 상태가 많다는 것은 특정 요청이 끝나기를 기다리는 프로세스가 많다는 것으로, 이 프로세스들은 요청이 끝나면 다시 R로 돌아가게 되어 시스템의 부하를 계산하는데 포함된다.

출처: cs.rutgers.edu

만일 특정 프로세스가 'D'상태에 오래 머무른다면 아래와 같이 원인을 생각해볼 수 있다.

- 스토리지의 I/O가 종료되지 않은 상태로 되어 있다.

- 커널 내에 문제가 발생했다.


S : Sleeping 상태로써 동작이 중지된 상태이다. 일시 정지 된 상태로 인터럽트 신호를 받을 때 까지 멈춰있게 된다. D 옵션과 달리 언제든 시그널을 받게 되면 바로 R 상태로 진입하여 처리가 가능하다. 시스템 콜 등을 호출하여 타이머를 작동시키거나, 콘솔의 입력을 기다리는 프로세스들의 상태이다. 시그널을 받았을 때 처리할 수 있도록 Interruptible 상태로 마킹 후 대기상태로 변환된다.

sleep, 터미널의 입력대기가 이런 상태로 진입하게 된다.


Z: 좀비 상태의 프로세스이다. 부모 프로세스가 죽은 자식 프로세스를 의미. Fork()를 통해 새로운 자식 프로세스를 실행시키고 부모 프로세스가 비정상적인 동작으로 죽었을 경우 자식 프로세스는 자신이 종료될 곳을 알려줄 방법이 없어 좀비 프로세스가 된다. 이미 사용 중지된 프로세스 이므로, CPU를 사용하지 않으며 메모리를 사용하지도 않는다. 하지만 PID를 소유하고 있으므로 PID 고갈이 일어날 수 있다.



이제 Load Average 가 무엇이며, Load Average에 포함되어 판단될 수 있는 프로세스의 종류를 알아보았다. 그렇다면 이제 직접 Load Average를 명령어를 통해 확인하는 방법을 알아보자.


Load Average를 확인할 수 있는 방법은 여러 가지가 존재한다.


1. uptime

[centos@ip-172-31-27-12 ~]$ uptime

 12:10:03 up 25 days, 22:04,  2 users,  load average: 0.04, 0.07, 0.05


uptime은 현재 서버의 구동 시간과 접속된 유저의 수, 그리고 가장 필요한 load average를 좌측부터 1분, 5분, 15분 단위의 값을 보여준다.


2. /proc/loadavg

[centos@ip-172-31-27-12 ~]$ cat /proc/loadavg

0.01 0.05 0.05 1/1166 28247


커널이 작성한 /proc/loadavg에는 좌측부터 1분, 5분, 15분 단위의 load average를 보여준다. 우측의 두 개는 (현재 cpu가 수행하고 있는 스레드 수 / 커널 스케줄러의 총 스레드 수), 최근 실행한 프로세스 아이디+1이다.


3. top

[centos@ip-172-31-27-12 ~]$ top -b -n 1 | grep -i load

top - 12:15:15 up 25 days, 22:09,  2 users,  load average: 0.17, 0.12, 0.07


top 명령어를 수행하면 uptime과 동일한 부분이 상단에 표현되는 것을 확인할 수 있다.


4. w

[centos@ip-172-31-27-12 ~]$ w

 13:46:46 up 25 days, 23:40,  2 users,  load average: 0.08, 0.06, 0.11

USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT

centos   pts/1    218.148.45.186   12:10    6.00s  0.05s  0.24s sshd: centos [priv]

centos   pts/0    218.148.45.186   11:05    2:41m  0.02s  0.02s -bash


위 역시 uptime 내용 아래 연결된 user정보가 나온다.



Load Average가 높아졌을 때 어떻게 해야 할까? 무엇이 원인이고 어떻게 해결해나갈지 알아보자.

Load Average는 앞서 설명한 것처럼 D와 R의 상태를 지닌 프로세스의 개수가 핵심이라고 했다. 이 말을 잘 생각해보면, Load Average가 높을때 R 상태의 프로세스의 개수가 많아서인지 또는 D 상태의 프로세스가 많아서 인지 구분해야 한다는 말이다.


R의 상태는 실행 중인 프로세스로 CPU 리소스를 사용 중인 상태라고 했다. 즉, CPU 리소스 부하를 의미한다.

D의 상태는 네트워크 또는 디스크의 응답을 대기하는 상태. 즉, I/O 부하를 의미한다.


while 문을 사용하여 무제한 연산하는 프로그램이나, fopen을 통해 계속해서 파일을 열고 닫는 프로그램이나 Load Average는 동일하게 상승한다. 하지만 이 둘은 엄연히 다른 종류의 부하이다.


그렇다면 이 두 가지의 부하를 어떻게 구분할 수 있을까?


바로 vmstat이라는 툴을 사용해서 알 수 있다.

vmstat(Virtual Memory Statics의 함축)은 현재 메모리 및 CPU의 사용률을 알 수 있는 툴이다.

직접 한번 실행해보자.


[centos@ip-172-31-27-12 ~]$ vmstat

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----

 r  b   swpd   free         buff        cache        si   so    bi    bo   in   cs us sy id wa st

 0  0      0     326616    441872  14563468    0    0     0     1       0    0   0   0 100  0  0


앞의 두 r과 b에 주목할 필요가 있다.

r은 실행되기를 기다리거나 실행 중인 프로세스의 개수를 나타내며, b는 uninterruptible sleep 상태의 프로세스로 I/O를 위해 대기열에 있는 프로세스의 개수를 나타낸다. 그러므로 r은 R 상태의 프로세스 개수이며 b는 D 상태의 프로세스 개수를 나타낸다.


즉, load average가 높아졌을때는 vmstat 을 통해 CPU 리소스 부하(R) 때문인지 I/O 부하(D) 때문인지 원인 파악이 가능하다.



각 CPU 코어마다 running 중인 프로세스와 개수는 어떻게 파악할 수 있을까?


각 코어가 기준이 아니라면 단순히 top 명령어를 통해 'S' 필드의 값이 R인 프로세스를 찾아도 된다. 그런데 각 코어 별 running 프로세스의 정보를 알고 싶다면 어떻게 해야 할까?


/proc/sched_debug 파일을 확인하면 된다. /proc/sched_debug는 실행 스케줄러 현재 조율 값, CFS 통계, 모든 사용 가능한 CPU에서 실행 큐 정보를 출력한다. 따라서 각 코어별 R 상태의 개수와 해당 프로세스를 파악할 수 있다.


그럼 각각의 부하는 시스템에 동일한 영향을 미칠까?


CPU 리소스 사용률이 높은 CPU 부하는 I/O 부하와 달리 CPU 점유율에 있어서 경쟁상태가 된다. 특정 프로세스가 장시간 I/O를 점유하고 있으면 같은 자원을 사용하려는 다른 프로세스의 I/O 처리를 위한 대기시간에 크게 영향을 미치기 때문에 겉으로 보기에는 Load Average가 높지 않지만 실제 시스템에서 I/O 및 Buffer를 거치는 작업 등에서 지연을 경험 할 수도 있다. 반대로 Load Average가 높지만 다른 프로세스와 동일한 자원을 사용하지 않는 I/O 처리 대기나 프로세스 간에 Context switching이 원활 할 경우에는 성능저하가 별로 느껴지지 않을 수도 있다.

즉, CPU 리소스를 서로 점유하기 위하여 경쟁하게 되며 이는 해당 프로세스의 성능 저하로 이어지게 된다.

반면에 I/O 부하의 경우에는 상대적으로 CPU 경쟁이 낮다 보니 CPU 부하와 다른 결과가 나오게 된다.

그렇다면 CPU 부하(R)보다 I/O 부하(D)가 더 나은 걸까? 그건 아니다. 다만 결과가 다르다는 것은 확실하다.



그럼 해결방안은?

R 프로세스가 많다는 것은 CPU 리소스 부하를 발생시키는 프로세스가 많다는 것으로 해석할 수 있다.

대표적으로 다음과 같은 두 가지로 나눌 수 있다.


1. CPU, 메모리 사용량 이외에는 정상적인 경우

2. 특정 프로그램의 CPU 점유율이 매우 높은 경우


전자의 상태에의 경우, 프로그램의 로직이나 알고리즘을 개선 또는 하드웨어 개선을 통해서 대응해야 한다.

후자의 경우는 오류를 제거해서 프로그램이 정상 동작하도록 수정해야 한다.


D 프로세스가 많다는 것은, I/O 요청으로 인한 대기중인 프로세스가 많다는 것이다. 다음 두 가지로 해석 가능하다.


1. 프로그램으로부터 입출력이 많아서 부하가 높은 경우

2. Swapping이 발생해서 디스크 액세스가 발생하고 있는 상황인 경우


전자의 경우 프로그램의 파일 입출력 부분을 개선해서 대응한다.

후자의 경우에는 특정 프로세스가 극단적으로 메모리를 소비하고 있지 않은지를 ps로 확인하며, 프로그램의 오류로 메모리를 지나치게 사용하고 있는 경우에는 프로그램을 개선한다. 또는 물리적인 램을 증설하는 방법이 있다.



마치며


지금까지 Load Average에 대해서 알아보았다. 사실 필자는 Load Average를 그간 CPU 점유율의 평균이라고 생각하고 있었다. 이는 반은 맞고 반은 틀리다고 할 수 있겠다. CPU 점유율이라 하면 R 상태를 표현하는 것이니...? 죄송합니다

여하튼, 이번 자료를 작성하면서 다양한 방법을 통해 문제점을 파악하고 찾아가는 것의 재미를 느끼고 있다.

리눅스 커널은 알아가면 알아갈수록 참 재미있는 것 같다.



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari