지난 회차에서 우리는 시스템 자원을 실시간으로 감시하고, CPU와 메모리를 비정상적으로 점유하는 폭주 프로세스를 색출해 내는 ps, top, htop 명령어의 활용법에 대해 알아보았습니다. 장애를 유발하는 프로세스의 PID(프로세스 ID)를 정확히 찾아냈다면, 이제는 그 프로세스를 안전하고 확실하게 정리하여 서버 자원을 회수할 차례입니다.
리눅스 환경에서 프로세스를 종료하는 행위는 단순히 프로그램을 '끄는' 것 이상의 의미를 가집니다. 커널(Kernel)은 프로세스에 시그널(Signal, 신호)이라는 특수한 메시지를 보내어 소통하며, 프로세스는 이 신호를 받았을 때 자원을 정리하고 종료할지, 혹은 즉시 소멸할지를 결정합니다.
만약 시그널의 메커니즘을 모른 채 무작정 강제 종료 명령어만 남발하면 데이터베이스 파일이 깨지거나, 공유 메모리 자원이 반환되지 않아 서버를 재부팅해야 하는 2차 장애로 이어질 수 있습니다. 이번 9회차에서는 프로세스 제어의 핵심인 리눅스 시그널의 종류와 kill, killall, pkill 명령어를 활용한 실무 프로세스 정리 기술을 상세히 다루어 보겠습니다.
리눅스 커널이 프로세스에 이벤트를 전달하는 비동기식 알림 체계를 '시그널'이라고 합니다. 리눅스에는 수십 가지의 시그널이 정의되어 있지만, 시스템 관리자가 프로세스를 제어할 때 사용하는 핵심 시그널은 다음 4가지로 요약됩니다.
의미: 터미널 접속이 끊겼을 때 발생하거나, 프로세스에 설정 파일을 재로딩(Reload)하라고 지시할 때 사용합니다.
설명: Nginx나 SSH 같은 데몬 프로그램들은 실행 중인 상태에서 1번 시그널을 받으면, 서비스를 중단(다운타임)하지 않고 /etc 하위의 환경 설정 파일만 다시 읽어와 적용하는 똑똑한 메커니즘을 가지고 있습니다.
의미: 사용자가 인터럽트를 걸어 프로세스를 전면 중단시킵니다.
설명: 터미널에서 어떤 명령어나 스크립트가 실행 중일 때, 키보드로 Ctrl + C를 누르는 행위가 바로 커널을 통해 프로세스에 2번 SIGINT 시그널을 던지는 것입니다.
의미: 프로세스에게 "정상적으로 종료해 달라"고 요청하는 표준 소프트웨어 종료 신호입니다.
설명: kill 명령어의 기본값입니다. 이 신호를 받은 프로세스는 하던 작업을 마무리하고, 열려 있던 파일 서술자(File Descriptor)를 닫으며, 데이터베이스 트랜잭션을 안전하게 커밋하거나 롤백한 뒤, 메모리를 커널에 반환하고 우아하게 소멸(Graceful Shutdown)합니다. 안전한 데이터 보호를 위해 가장 먼저 던져야 하는 신호입니다.
의미: 프로세스를 무조건 강제 종료합니다.
설명: 이 신호는 프로세스를 거치지 않고 커널이 프로세스를 그 자리에서 즉시 소멸시킵니다. 프로세스 입장에서는 방어하거나(Catch), 무시(Ignore)할 수 없는 절대적인 명령어입니다. 하지만 작업을 정리할 기회를 주지 않으므로 데이터 유실이나 파일 시스템 오염을 유발할 수 있어, 15번 신호에 반응하지 않는 먹통 프로세스에만 제한적으로 사용해야 합니다.
kill 명령어는 가장 전통적이고 강력한 시그널 전송 도구입니다. 이름은 '죽이다'이지만 실제 기능은 '지정한 PID에 특정 시그널 번호를 배달하는 것'입니다.
Bash
kill [시그널_번호_또는_이름] PID
자원을 독점하여 시스템을 느리게 만드는 특정 자바 애플리케이션(PID: 8847)이 포착된 상황에서의 조치 단계입니다.
Bash
# 1단계: 가장 안전한 15번(SIGTERM) 신호를 먼저 보냄 (시그널 번호를 생략해도 기본 15번으로 작동)
kill -15 8847
# 2단계: ps나 top으로 프로세스가 자원을 정리하고 완전히 사라졌는지 2~3초간 대기하며 확인
ps -fp 8847
# 3단계: 만약 프로세스가 세그멘테이션 폴트나 데드락에 빠져 15번 신호를 무시하고 버틴다면,
# 최후의 수단으로 9번(SIGKILL) 강제 종료 신호를 하달하여 즉각 소멸시킴
kill -9 8847
Nginx 설정 파일(nginx.conf)을 수정 수정한 후, 서비스를 끄지 않고 설정을 반영하고 싶을 때는 마스터 프로세스에 1번(SIGHUP) 신호를 보냅니다.
Bash
# Nginx 마스터 프로세스의 PID가 1024번일 때
kill -1 1024
kill 명령어는 정확하지만 매번 ps를 쳐서 PID를 알아내야 하므로 수십 개의 프로세스가 동시에 생성되는 환경(예: 웹 서버 워커 프로세스, 다중 파이썬 크롤러 등)에서는 작업 효율이 떨어집니다. 이때 프로세스의 명칭이나 패턴을 기반으로 일괄 제어할 수 있는 도구가 killall과 pkill입니다.
지정한 프로세스 명칭과 100% 일치하는 모든 프로세스를 찾아서 시그널을 보냅니다.
웹 서버 부하로 인해 수십 개로 포크된 httpd 프로세스들을 일시에 안전하게 정리해야 하는 상황입니다.
Bash
# 이름이 httpd인 모든 프로세스에 SIGTERM(15) 시그널을 일괄 전송
sudo killall httpd
# 만약 강제로 전부 죽여야 한다면
sudo killall -9 httpd
pkill은 단어의 일부분만 매칭되어도 프로세스를 찾아내며, 특정 계정(-u)이 실행한 프로세스만 골라 죽이는 등의 고차원적인 조건부 필터링 종료를 지원합니다.
퇴사했거나 인가되지 않은 특정 사용자 계정(bad_user)이 서버 백그라운드에 세션을 유지한 채 대량의 파이썬 스크립트(python3_script.py)를 무단 구동하고 있는 보안 위협 상황입니다.
Bash
# bad_user(-u) 소유의 프로세스 중 명칭에 'python' 패턴이 포함된 모든 프로세스를 9번으로 강제 종료
sudo pkill -9 -u bad_user python
프로세스를 제어하다 보면 kill -9를 아무리 날려도 죽지 않고 ps 출력 결과에 [defunct] 또는 상태 코드 Z로 표시되는 유령 같은 프로세스를 만나게 됩니다. 이를 좀비 프로세스라고 부릅니다.
자식 프로세스가 자기 업무를 마치고 종료되면 종료 상태 코드(Exit Status)를 메모리에 남기고 소멸합니다. 이때 부모 프로세스가 wait() 시스템 콜을 호출하여 이 종료 코드를 수거해 가야 비로소 자식 프로세스의 흔적이 메모리 테이블에서 완벽히 지워집니다.
하지만 부모 프로세스가 버그나 고인 상태(Hang)에 빠져 이 코드를 수거하지 않으면, 자식 프로세스는 이미 죽었음에도 최소한의 메타데이터(PID)를 붙잡은 채 메모리 맵에 좀비 상태로 누적되게 됩니다.
좀비 프로세스는 이미 죽은 상태이기 때문에, 좀비 본인의 PID에 kill -9 신호를 아무리 보내봤자 아무런 반응을 하지 않습니다. 좀비를 없애는 유일한 방법은 그 좀비를 방치하고 있는 부모 프로세스(PPID)를 찾아내어 정리하는 것입니다.
Bash
# 1. 좀비 프로세스의 부모 PID(PPID)를 확인 (ps의 -o 옵션으로 필수 필드만 지정 출력)
ps -eo pid,ppid,stat,cmd | grep -w "Z"
# 출력 결과 예시: 9912 8800 Z [python] <defunct>
# 해석: PID 9912는 좀비(Z) 상태이며, 이 좀비의 부모는 8800번입니다.
# 2. 좀비를 방치하는 부모 프로세스(8800)에게 정상 종료 신호를 보냄
kill -15 8800
# 3. 만약 부모 프로세스가 종료되면, 좀비 프로세스들은 최상위 부모인 1번 프로세스(init 또는 systemd)에게 입양됩니다.
# 1번 프로세스는 주기적으로 wait()을 돌려 좀비들을 깨끗하게 메모리에서 지워줍니다.
리눅스 시스템 인프라를 안정적으로 가동하고 장애 요소를 제거하기 위해서는 프로세스를 죽이는 행위 뒤에 숨겨진 커널 시그널 체계를 명확히 통제할 수 있어야 합니다.
시스템 중단 없이 설정을 동적으로 반영할 때는 kill -1 (SIGHUP)을 활용하고,
프로세스가 열어둔 자원과 데이터 무결성을 보호하며 우아하게 종료시킬 때는 항상 kill -15 (SIGTERM)를 최우선으로 던져야 하며,
이에 불응하는 데드락 프로세스에 한해서만 최후의 수단으로 kill -9 (SIGKILL)를 제한적으로 사용해야 합니다.
대량의 프로세스를 조건부로 엮어 일괄 정리할 때는 killall과 pkill로 능률을 높이고,
메모리 테이블을 오염시키는 좀비 프로세스는 본인이 아닌 부모 PID(PPID)를 추적하여 근본적으로 척결해야 합니다.
이 시그널 제어 원칙을 실무에 철저히 적용할 때, 데이터 오염으로 인한 복구 불가능한 장애를 미연에 방지하고 시스템 자원을 항상 최상의 상태로 유지하는 프로 엔지니어로 성장할 수 있습니다. 다음 10회차에서는 이러한 프로세스들이 발을 딛고 있는 물리적 기반인 '시스템 자원 및 스토리지 점검(df, du, free)' 기술에 대해 자세히 알아보겠습니다.