서버관리_15 CPU 사용률 감시하기

 
  • 출처 : 유닉스 리눅스 쉘스크립트 예제사전_한빛미디어

명령어: mpstat, tail, awk, echo, date, iostat
키워드: CPU, 부하, idle, 이용률, 감시
사용처: CPU 부하를 정기적으로 감시해서 idle 값이 낮아지면 경고를 출력하고 싶을 때

실행 예제

$ ./cpu-idlecheck.sh
[2023/09/08 15:15:15] CPU %idle Alert: 4.53 (%)
ALERT...

스크립트

#!/bin/sh

# 감시할 CPU %idle 허용값. 이 값 이하면 경고
idle_limit=10.0 # ------------------------------------------ 1

# CPU %idle을 mpstat 명령어로 취득, 마지막 줄의 평균값을 추출
cpu_idle=$(mpstat 1 5 | tail -n 1 | awk '{print $NF}') # --- 2

#현재 %idle과 허용값을 bc 명령어로 비교
is_alert=$(echo "$cpu_idle < $idle_limit" | bc) # ---------- 3

# 경고할 것인지 판별
if [ "$is_alert" -eq 1 ]; then # --------------------------- 4
  # 현재 시각을 [2023/09/08 15:15:15] 형태로 조합
  date_str=$(date +'%Y/%m/%d %H:%M:%S') # ------------------ 5

  # CPU %idle 저하를 경고로 출력
  echo "[$date_str] CPU %idle Alert: $cpu_idle (%)" # ------ 6
  /home/user1/bin/alert.sh
fi

해설

이 스크립트는 최근 5초간 CPU 사용률을 조사해서 CPU 부하를 감시합니다. 여기서 CPU 부하란 CPU 아이들값인 %idle(CPU가 미사용 상태였던 시간 비율)을 계측합니다.

예제에서는 mpstat 명령어로 CPU %idle을 취득해서 셸 변수 idle_limit로 지정한 값보다 최근 5초간 %idle 평균값이 작으면 CPU 리소스가 부족하다고 판별해서 alert.sh 스크립트를 실행합니다. 이 예제에서 alert.sh는 알림 메일을 보내는 등 경고를 출력하는 스크립트라고 가정합니다. 환경에 맞게 수정해서 사용하기 바랍니다.

애플리케이션 서버에서는 프로그램이 예상하지 못한 무한 반복을 하거나 무거운 처리를 오랫동안 실행하는 등의 이유로 서버 부하가 높아져서 CPU 처리가 따라오지 못하는 경우가 있습니다. 그렇게 CPU 리소스가 부족하면 서버 전체 처리 속도가 떨어져서 사용자에 응답 시간도 늘어나게 됩니다. CPU가 시스템 보틀넥이 되진 않는지 모니터하기 위해 이런 스크립트가 도움이 될 것입니다.

CPU 이용 상태를 취득하려면 리눅스에서는 mpstat 명령어가 편리합니다. mpstat 명령어 출력은 다음과 같습니다.

$ mpstat 1 3
$ mpstat 1 3
Linux 3.10.0-229.el7.x86_64 (localhost.localdomain)		06/11/2021	_x86_64_	(1 CPU)

12:12:12 AM	CPU	%usr	%nice	%sys	%iowait	%irq	%soft	%steal	%guest	%gnice	%idle
12:12:13 AM 	all	8.00	0.00	0.00	0.00	0.00	0.00	0.00	0.00	0.00	92.00	
12:12:14 AM 	all	15.00	0.00	2.00	0.00	0.00	0.00	0.00	0.00	0.00	83.00	
12:12:15 AM 	all	13.13	0.00	0.00	0.00	0.00	0.00	0.00	0.00	0.00	86.87
Average:	all	12.04	0.00	0.67	0.00	0.00	0.00	0.00	0.00	0.00	87.29

mpstat 명령어 인수에 1 3을 지정했습니다. 첫 인수가 인터벌로 몇 초마다 계측하지 지정합니다. 1이므로 1초마다입니다. 두 번째 인수가 몇 번 계측할지를 결정하는데 여기서는 3회 계측합니다.

많은 항목이 있지만 CPU 부하를 간단히 보려면 마지막에 있는 평균값(Average)의 %idle만 보면 충분합니다. 이 값이 극단적으로 낮으면 CPU 부하가 높은 상태라고 할 수 있습니다. 예제에서도 이 값을 사용합니다.

그럼 예제를 살펴봅시다. 1에서 우선 CPU %idle 감시 허용값을 설정합니다. 이 값보다 현재 CPU %idle값이 작으면 CPU 부하가 높다고 판단하고 경고를 출력합니다. 여기서는 10.0%로 잡습니다.

2에서는 mpstat 명령어 출력에서 최근 5초간 CPU %idle 평균값을 취득합니다. 실행예에서 보았듯 마지막 줄 가장 오른쪽 값(예에서는 87.29)에 취득하고 싶은 CPU %idle 평균값이 출력되므로 이것을 추출합니다. 2는 우선 mpstat 명령어를 실행하고 파이프로 tail 명령어에 줄 수 지정 옵션 -n 1을 지정해서 마지막 줄만 표시합니다. 그리고 awk 명령어 {print $NF}로 액션 지정을 하면 마지막 컬럼만 표시하게 됩니다. $NF는 awk 변수로 마지막 컬럼을 의미합니다.

3에서 취득한 CPU %idle의 정의해둔 허용값 이하인지 판정합니다. 셸 스크립트에서 숫자 비교는 정수라면 expr 명령어를 사용하지만 소숫점을 다룬다면 bc 명령어를 사용합니다. bc 명령어는 다음처럼 echo 명령어로 대소비교식을 표준 입력으로 넘겨서 비교 결과를 출력할 수 있습니다. 참이면 1, 거짓이면 0이 됩니다.

  • bc 명령어 대소 비교
    $ echo "1.1 > 2.5" | bc
    0 # --------------------- '1.1은 2.5보다 큰가?'는 거짓이므로 0'
    $ echo "1.1 < 2.5" | bc
    1 # --------------------- '1.1은 2.5보다 작은가?'는 참이므로 1'
    

이렇게 해서 3에서 셸 변수 is_alert에 경고할 것인지 플래그를 설정합니다. 4의 if문으로 분기합니다. is_alert이 참(값이 1)이면 CPU %idle은 허용값 이상이므로 if문에서 경고 처리를 실행합니다.

5에서 date 명령어를 사용해서 현재 시각을 2023/09/08 15:15:15처럼 조합합니다. 이런 감시 스크립트는 문제 발생 시작 기록이 중요합니다.

마지막으로 6에서 경고 표시를 하고 CPU %idle값을 출력합니다. 이런 스크립트를 cron에 등록해서 정기적으로 서버 CPU 부하 상태를 감시할 수 있습니다.

FreeBSD/Mac의 경우

FreeBSD 및 Mac은 mpstat 명령어가 없으므로 iostat 명령어를 이용합니다. iostat 명령어 출력 예는 다음과 같습니다.

  • FreeBSD iostat 명령어
    $ iostat 1 3
      tty			vtbd0		vtdb1		cpu
    tin	tout	KB/t	tp	MB/s	KB/t	tps	MB/s	us	ni	sy	in	id
    0	6	27.66	12	0.32	59.39	24	1.37	9	0	4	0	87
    0	183	0.00	0	0.00	0.00	0	0.00	11	0	3	0	86
    0	61	0.00	0	0.00	38.04	135	5.01	5	0	3	0	92
    
  • Mac iostat 명령어
    $ iostat 1 3
      disk0		disk1		disk2		cpu		load average
    KB/t	tps	MS/s	KB/t	tps	MB/s	KB/t	tps	MB/s	us	sy	id	1m	5m	15m
    36.19	14	0.49	116.11	2	0.22	255.42	0	0.07	5	2	93	1.71	1.71	1.62
    15.05	20	0.29	0.00	0	0.00	0.00	0	0.00	3	5	92	1.71	1.71	1.62
    0.00	0	0.00	0.00	0	0.00	0.00	0	0.00	4	4	92	1.66	1.70	1.62
    

위 예처럼 Mac과 FreeBSD도 조금씩 다른데 CPU %idle은 cpu 항목에서 id라는 값입니다. FreeBSD에서는 마지막 컬럼입니다. 한편, Mac은 뒤에서 4번째 컬럼입니다. iostat 명령어 출력 컬럼은 마운트한 디스크 숫자에 따라 변하므로 CPU 이용률을 확인하려면 이렇게 뒤에서부터 세는 것이 편리합니다.

iostat 명령어는 vmstat 명령어와 마찬가지로 첫 줄은 현재값이 아니라 시스템 기동 때부터의 평균값을 표시합니다. 따라서 감시할 때는 첫 줄을 무시하는 것이 보통입니다.

iostat 명령어는 mpstat 명령어와 달리 평균값을 출력하지 않으므로 스스로 계산해야합니다. awk 명령어로 id 컬럼 숫자값을 더해서 처리 줄 수로 나누면 평균값을 구할 수있습니다. 구체적으로는 2 부분을 다음처럼 수정합니다. 여기서 iostat 1 6으로 측정값을 6번 출력하는데 첫 번째 줄은 무시하고 5개 값을 사용합니다. 따라서 awk 명령어로 평균값을 구할 때도 5.0으로 나눕니다.

# FreeBSD
cpu_idle=$$(iostat 1 6 | awk 'NR >= 4 {sum += $NF} END{print sum/5.0}')

# Mac
cpu_idle=$$(iostat 1 6 | awk 'NR >= 4 {sum += $(NF-3)} END{print sum/5.0}')

iostat 명령어로 CPU %idle 평균값을 계산살 때 6번 출력하고 첫 줄은 무시합니다. 그리고 Mac은 뒤에서부터 4번째 컬럼값을 추출하려면 마지막 컬럼을 나타내는 awk 변수 NF에서 3을 뺍니다.

주의사항

  • 리눅스는 설치 옵션에 따라 mpstat 명령어가 기본 설치되지 않을 수도 있습니다. 명령어를 찾지 못하면 mpstat 명령어가 포함된 sysstat 패키지를 설치하기 바랍니다.

  • mpstat 명령어로 표시되는 CPU %idle값 등은 여러 CPU가 있을 때 그 평균값이 됩니다. 예를 들어 CPU 2개 있는 머신에서 멀티 프로세서 대응하지 않은 프로세스가 한쪽만 CPU 리소스를 압박한다면 한쪽 CPU는 idle이 0%(완전가동), 다른쪽 CPU는 idle이 100%(아무것도 하지 않음)가 됩니다 .하지만 mpstat 명령어로는 평균값만 나오므로 이럴 때는 idle이 50%라고 표시됩니다 .CPU마다 CPU 사용률을 표시하고 싶으면 mpstat 명령어에 -P ALL 옵션을 이용하기 바랍니다.

  • 멀티 프로세서 명령어 사용 예
    $ mpstat -P ALL 1 3
    (생략)
    Average: CPU	%usr	%nice	 %sys	%iowait	%irq	%soft	%steal	%guest	%idle
    Average: all	36.38	 0.00	13.62	   0.00	0.00	 0.00	  0.17	  0.00	49.83
    Average:   0	72.76	 0.00	27.24	   0.00	0.00	 0.00	  0.00	  0.00	 0.00
    Average:   1	 0.00	 0.00	 0.00	   0.00	0.00	 0.00	  0.66	  0.00	99.34
    
  • CPU idle 감시를 셸 스크립트로 하는 것은 소규모 환경에서 보조적인 용도로 사용한느 경우가 많습니다. 대규모의 시스템이라면 자빅스나 나기오스 이용을 검토해보기 바랍니다.