서버관리_08 특정 프로세스가 정지했는지 감시하기

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

명령어: ps, grep, wc
키워드: 프로세스, 감시, 정지
사용처: 서비스 제공 시 존재해야 할 프로세스가 정지하지 않았는지 감시하고 싶을 때 사용합니다.

실행 예제

$ ./process-isalive.sh
[ERROR] 프로세스 /usr/llibexec/mysqlid 찾지 못했습니다.
start alert.sh ...

스크립트

#!/bin/sh

# 감시할 프로세스 명령어
commname="usr/libexec/mysqld" # -------------------------------------------------- 1

# 대상 명령어 프로세스 수를 카운트
count=$(ps ax -o command | grep "$commname" | grep -v "^grep" | wc -l) # ^grep --- 2

# grep 명령어 출력 결과가 0이면 프로세스가 존재하지 않으므로
# 알림 처리하기

if [ "$count" -eq 0]; then #if문 -------------------------------------------------- 3
  echo "[ERROR] 프로세스 $commname 찾지 못했습니다." >&2
  /home/user1/bin/alert.sh
fi

해설

이 스크립트는 지정한 프로세스가 존재하는지 감시합니다. 여기서 MySQL 서버 프로세스 /usr/libexec/mysqld가 실행되었는지 감시해서 없으면 프로세스가 다운됐다고 보고 alert.sh를 실행합니다. 그리고 예제에서는 alert.sh가 통지 메일을 송신하는 등 경고 처리를 하는 스크립트라고 가정합니다. 여러분은 상황에 맞춰 변경하거나 다른 통지 방법으로 응용하기 바랍니다.

서버 운용 시 프로세스가 어느새 정지하는 문제는 자주 벌어집니다. 서버 자체의 생존 여부는 ping 명령어로 하더라도 프로세스가 죽으면 정상적으로 서비스할 수 없습니다. 따라서 프로세스 감시 구조는 서비스를 제공하기 위한 중요한 요소입니다. 여기서는 셸 스크립트를 써서 프로세스가 존재하는지 확인하는 예를 살펴봅시다.

예제는 1 에서 감시할 프로세스를 지정합니다. 명령어 이름으로 프로세스를 확인하므로 리눅스(CentOS)에서 MySQL을 rpm으로 설치할 때 실행 명령어 /usr/libexec/mysqld를 지정합니다.

2 에서 우선 ps 명령어 -ax 옵션으로 모든 프로세스를 표시하고 -o 옵션으로 표시 항목을 지정합니다 .”-o command”라고 지정하므로 명령어 이름 항목만 표시합니다.

  • 모든 프로세스 명령어 이름만 표시
    $ ps ax -o command
    COMMAND
    /sbin/init
    [kthreadd]
    [migration/0]
     (생략)
    sshd: park [priv]
    sshd: park@pts/0
    

이것은 프로세스 감시에 필요 없는 문자열이나 숫자가 들어 있으면 잘못 인식할 수 있기 때문입니다. 그리고 -o 옵션은 BSD 옵션에는 없으므로 리눅스에서 사용할 때도 하이픈을 함께 지정합니다.

2 의 ps 명령어 출력은 파이프에 넘겨서 grep 명령어를 실행해서 셸 변수 commname으로 지정한 명령어 이름과 일치하는지 확인합니다. 그리고 한 번 더 파이프로 이어서 grep -v “^grep”을 합니다. 이것은 예전부터 자주 사용하던 방법으로 여러분도 인수받은 셸 스크립트를 보다보면 자주 등장할 것입니다.

grep 명령어 -v 옵션은 그 패턴을 포함한 줄을 제거하는 옵션입니다. 왜 이 명령어를 사용할까요? 단순히 mysqld 프로세스를 감시한다고 grep “/usr/libexec/mysqld”라고하면 이 grep 명령어 자체가 ps 명령어 목록에 들어 있어서 잘못 인식되기 때문입니다.

  • ps 명령어 결과를 확인하는 grep 명령어가 포함됨
    $ ps ax -o command | grep "/usr/libexec/mysqld"
    grep /usr/libexec/mysqld
    

따라서 grep 명령어 자체를 제거하기 위해 grep -v “^grep”을 지정합니다. 2 는 마지막에 wc 명령어 줄 수를 세는 -l 옵션을 써서 일치한 줄 수를 카운트하고 명령어 치환 $()로 셸 변수 count에 대입합니다. 이것이 감시 대상 프로세스 수가 됩니다.

3 은 감시 통지를 할 것인지 판별합니다. 셸 변수 count에는 grep 명령어에 일치한 줄 즉, 프로세스 수가 들어 있습니다. 같은지 어떤지 판별하는 -eq 연산자로 비교해서 이것이 0이라면 프로세스가 존재하지 않는다는 의미입니다. 따라서 프로세스를 찾지 못하면 메시지를 echo 명령어로 표시하고 이어서 감시 통지를 하는 alert.sh를 실행합니다.

ps 명령어 설명

ps 명령어는 서버에서 동작하는 프로세스를 표시하는 프로그램입니다. ps 명령어는 오래된 역사를 지니고 있어서 옵션 지정도 각각이라 다루기 까다롭습니다. 이 ps 명령어는 크게 두 종류의 옵션 형태가 있습니다.

  • UNIX 옵션: 솔라리스에서 사용한 옵션 형식
  • BSD 옵션: FreeBSD 같은 BSD 계열 OS에서 사용한 옵션 형식

FreeBSD/Mac은 BSD 옵션을 사용할 수 있습니다. 한편 리눅스는 두 방법 다 사용할 수 있습니다. 하지만 리눅스 ps 명령어는 UNIX 옵션은 하이픈과 함께, BSD 옵션은 하이픈 없이 사용한다는 규칙이 있습니다. 그리고 FreeBSD 같은 BSD 계열 OS에서 BSD 옵션을 사용할 때도 하이픈을 생략하는 것이 보통입니다.

우선 UNIX 옵션 예를 살펴봅시다.

  • 주요 UNIX 옵션

    옵션 설명
    -a 터미널과 관련없는 프로세스를 제외한 모든 프로세스 표시
    -f 상세 정보 표시(사용자ID, 부모 프로세스 ID 등)
    -e 현재 실행 중인 모든 프로세스 표시

이어서 BSD 옵션을 살펴봅시다. 여기서는 설명을 위해 하이픈을 붙였지만 앞에서 이야기 했듯 일반적으로 실제로는 명령어를 실행할 때 하이픈을 붙이지 않습니다.

  • 주요 BSD 옵션

    옵션 설명
    -a 자신 이외의 사용자 프로세스 정보도 표시
    -x 제어 터미널이 없는 프로세스도 표시
    -l 상세 정보 표시(사용자 ID, 부모 프로세스 ID 등

그리고 양쪽 형식에서 사용 가능한 옵션이 있습니다.

  • 양쪽에서 사용 가능한 옵션

    옵션 설명
    -p 프로세스 ID 지정
    -u 실효 사용자 ID 지정
    -o 지정한 키워드 관련 컬럼만 표시

UNIX 형식과 BSD 형식 옵션 중에서 어느 쪽 옵션 형식을 사용하는지는 취향 문제지만 BSD 옵션 쪽을 선호하는 경우가 많습니다. 따라서 예제에서도 BSD 옵션을 채용해서 -a와 -x를 조합해서 모든 프로세스를 표시합니다. 그리고 BSD 옵션을 이용할 때는 기본적으로 하이픈 없이 이용하므로 예제의 ax 옵션도 하이픈이 없습니다.

주의사항

  • 프로세스 감시할 때 grep 명령어 자체를 잘못 검출하지 않도록 대응하는 방법은 예제에서 이용하는 grep -v “^grep” 외에도 다음과 같은 방법이 있습니다.
    ps ax -o command | grep "[/]usr/libexec/mysqld"
    

    이 방법은 감시하고 싶은 명령어 첫 문자를 문자 클래스 []에 넣어서 지정합니다. 여기서 문자 클래스 안에 /(슬래시)만 있으므로 실제로는 grep “/usr/libexec/mysqld”라고 적은 것과 같습니다. 하지만 이때 ps 명령어로 얻은 grep 명령어의 인수에는 대괄호가 있어서 /usr/libexec/mysqld 라는 문자열에 일치하지 않아서 잘못 검출하는 걸 피할 수 있습니다.

  • 이 스크립트는 명령어 이름으로 단순히 grep하므로 예를 들어 다음처럼 명령어 이름과 같은 문자열을 인수로 받는 프로그램이 있을 때 프로세스가 있다고 잘못 검출하게 됩니다.
    ./hoge_check /usr/libexec/mysqld