- Published on
프로세스와 시그널 완전 가이드: 종료가 안 되는 이유를 끝까지 추적하기
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 1. 프로세스 상태 — ps의 STAT 한 글자
- 2. 시그널 표 — 번호, 기본 동작, 용도
- 3. kill, pkill, killall — 누구에게 보내는가
- 4. SIGTERM과 SIGKILL — 유예를 설계하기
- 5. PID 1, 좀비, 고아
- 6. 프로세스 그룹, 세션, 그리고 터미널이 닫힐 때
- 7. 애플리케이션에서 시그널 다루기
- 8. 죽지 않는 프로세스를 계층별로 추적하기
- 9. 우선순위와 자원 한도
- 퀴즈: 실력을 확인해 보세요
- 마치며
- 참고 자료
- 이어서 읽기
들어가며
배포 스크립트에서 kill을 보냈는데 프로세스가 안 죽습니다. kill -9를 보냈는데도 목록에 남아 있습니다. 터미널을 닫았더니 백그라운드 작업이 함께 죽었습니다. 컨테이너를 정지시켰는데 애플리케이션이 데이터를 쓰다 말고 끊겼습니다.
네 가지 모두 같은 지식이 없어서 생기는 문제입니다. 시그널이 프로세스에 어떻게 전달되고, 누가 그것을 무시할 수 있으며, 어떤 상태에서는 아예 전달되지 않는가에 대한 지식입니다.
이 글은 시그널의 목록을 외우는 글이 아닙니다. 시그널이 프로세스 그룹과 세션, 컨트롤 터미널, 부모-자식 관계와 얽혀 만들어 내는 실제 운영 상황을 순서대로 다룹니다. 마지막에는 애플리케이션과 컨테이너에서 우아한 종료를 설계하는 방법까지 이어집니다.
기준은 리눅스 커널 5.x 이상, x86-64 및 ARM 아키텍처입니다. 시그널 번호는 아키텍처마다 다릅니다. 이 글의 번호는 x86/ARM 기준이며, Alpha, MIPS, SPARC 등에서는 다른 값을 씁니다. 스크립트에서는 항상 번호 대신 이름을 쓰는 편이 안전합니다.
1. 프로세스 상태 — ps의 STAT 한 글자
ps의 STAT 열은 그 프로세스에 무슨 일이 벌어지는지 한 글자로 요약합니다.
ps -eo pid,ppid,stat,wchan:24,etime,args --sort=-pcpu | head -20
| 코드 | 의미 | 실무적 함의 |
|---|---|---|
R | 실행 중 또는 실행 대기 | CPU를 쓰거나 받으려고 줄 서 있음 |
S | 중단 가능 대기 | 정상적인 대기. 시그널로 깨울 수 있음 |
D | 중단 불가 대기 | SIGKILL도 즉시 통하지 않음. 대개 디스크·NFS |
Z | 좀비 | 이미 죽었고 부모가 회수하지 않은 상태 |
T | 정지됨 | SIGSTOP 또는 SIGTSTP를 받음 |
t | 디버거에 의해 정지 | ptrace 중 |
I | 유휴 커널 스레드 | 무시해도 됨 |
부가 문자도 정보를 줍니다. s는 세션 리더, +는 포그라운드 프로세스 그룹, l은 멀티스레드, <는 높은 우선순위, N은 낮은 우선순위입니다.
D 상태가 보이면 시그널로는 해결되지 않습니다. 커널이 무엇을 기다리는지 확인하세요.
sudo cat /proc/1234/stack
sudo cat /proc/1234/wchan; echo
cat /proc/1234/status | grep -E '^State|^SigQ|^SigPnd|^SigBlk|^SigIgn|^SigCgt'
SigPnd는 대기 중인 시그널, SigBlk는 차단된 시그널, SigIgn은 무시로 설정된 시그널, SigCgt는 핸들러가 등록된 시그널의 비트마스크입니다. 십육진수 비트마스크라 읽기 번거롭지만, "이 프로세스가 SIGTERM을 잡고 있는가"를 확인하는 확실한 방법입니다.
2. 시그널 표 — 번호, 기본 동작, 용도
man 페이지 signal(7)에 정의된 표준 시그널 중 운영에서 실제로 쓰는 것들입니다. 번호는 x86/ARM 기준입니다.
| 시그널 | 번호 | 기본 동작 | 실무 용도 |
|---|---|---|---|
SIGHUP | 1 | Term | 설정 재적재 관례. 원래는 터미널 연결 끊김 |
SIGINT | 2 | Term | 키보드 인터럽트 |
SIGQUIT | 3 | Core | 코어 덤프 유발. JVM은 스레드 덤프를 출력 |
SIGKILL | 9 | Term | 잡을 수도 차단할 수도 무시할 수도 없음 |
SIGUSR1 | 10 | Term | 애플리케이션 정의. nginx는 로그 재오픈 |
SIGUSR2 | 12 | Term | 애플리케이션 정의. nginx는 바이너리 교체 |
SIGPIPE | 13 | Term | 읽는 쪽이 없는 파이프에 쓸 때 |
SIGTERM | 15 | Term | 정중한 종료 요청. 기본 kill 시그널 |
SIGCHLD | 17 | Ign | 자식이 종료·정지·재개됨 |
SIGCONT | 18 | Cont | 정지된 프로세스 재개 |
SIGSTOP | 19 | Stop | 잡을 수도 차단할 수도 무시할 수도 없음 |
SIGTSTP | 20 | Stop | 터미널에서 입력한 정지 |
기본 동작의 뜻은 Term(종료), Core(종료 후 코어 덤프), Ign(무시), Stop(정지), Cont(재개)입니다.
man 페이지가 명시하는 가장 중요한 문장은 이것입니다. SIGKILL과 SIGSTOP은 잡을 수도, 차단할 수도, 무시할 수도 없습니다. 나머지 시그널은 전부 애플리케이션이 처리 방식을 바꿀 수 있습니다. 그래서 kill -TERM이 통하지 않는 프로그램이 존재하는 것이고, 그것은 버그가 아니라 설계일 수 있습니다.
SIGPIPE는 파이프라인에서 자주 문제가 됩니다.
yes | head -1
head가 한 줄을 읽고 종료하면 yes는 읽는 쪽이 없는 파이프에 쓰게 되고 SIGPIPE로 종료됩니다. 이것이 정상 동작입니다. 그런데 SIGPIPE를 무시하도록 설정한 프로그램은 대신 EPIPE 오류를 받게 되므로, 오류 처리를 하지 않으면 무한 루프에 빠질 수 있습니다.
3. kill, pkill, killall — 누구에게 보내는가
kill -l
kill -TERM 1234
kill -s TERM 1234
kill -9 1234
kill -0 1234
kill -0은 시그널을 보내지 않고 전달 가능한지(프로세스 존재 여부와 권한)만 확인합니다. 스크립트에서 프로세스 생존 확인에 쓰기 좋습니다.
이름으로 보내는 도구는 두 종류이며 동작이 다릅니다.
pkill -TERM -f 'java.*myapp'
pkill -u appuser -TERM nginx
killall -TERM nginx
pgrep -a -f 'java.*myapp'
pgrep/pkill은 패턴 매칭이며,-f를 주면 명령줄 전체와 비교합니다.-f없이는 프로세스 이름(보통 15자로 잘린 값)만 봅니다.killall은 정확한 이름 일치입니다. 주의할 점은 일부 유닉스(Solaris 등)에서killall이 전혀 다른 의미로 동작한다는 것입니다. 이식성을 생각하면pkill이 안전합니다.
파괴적 명령 경고: pkill -f는 패턴이 넓으면 의도치 않은 프로세스까지 죽입니다. 특히 root로 실행할 때 위험합니다. 반드시 pgrep으로 먼저 대상을 확인한 다음 같은 패턴으로 pkill을 실행하세요.
# 1단계: 대상 확인 (아무것도 죽이지 않음)
pgrep -a -f 'java.*myapp'
# 2단계: 목록이 정확할 때만 실행
pkill -TERM -f 'java.*myapp'
프로세스 그룹 전체에 보내려면 PID 앞에 마이너스를 붙입니다. 음수 PID는 프로세스 그룹 ID를 뜻합니다.
kill -TERM -12345
이 형태는 자식까지 한 번에 정리할 때 유용하지만, 그룹 ID를 잘못 지정하면 광범위하게 영향을 줍니다. 특히 kill -9 -1은 권한이 닿는 모든 프로세스에 SIGKILL을 보내며, root로 실행하면 시스템을 사실상 정지시킵니다. 절대 실행하지 마세요.
4. SIGTERM과 SIGKILL — 유예를 설계하기
올바른 종료 절차는 항상 두 단계입니다. 먼저 SIGTERM을 보내고, 유예 시간을 준 뒤, 그래도 살아 있으면 SIGKILL을 보냅니다.
#!/usr/bin/env bash
set -euo pipefail
PID="$1"
TIMEOUT="${2:-30}"
kill -TERM "$PID" 2>/dev/null || exit 0
for _ in $(seq "$TIMEOUT"); do
if ! kill -0 "$PID" 2>/dev/null; then
echo "graceful shutdown complete"
exit 0
fi
sleep 1
done
echo "timeout, escalating to SIGKILL" >&2
kill -KILL "$PID"
SIGKILL은 애플리케이션에 정리할 기회를 주지 않습니다. 열린 파일의 버퍼는 플러시되지 않고, 트랜잭션은 중단되며, 임시 파일과 락 파일은 남습니다. 데이터베이스나 큐 소비자에게 SIGKILL을 보내는 것은 사실상 전원을 뽑는 것과 같습니다. 유예 시간을 넉넉히 주는 편이 언제나 낫습니다.
systemd 서비스에서는 이 절차가 설정으로 제공됩니다.
[Service]
KillSignal=SIGTERM
TimeoutStopSec=60
KillMode=mixed
SendSIGKILL=yes
KillMode=mixed는 메인 프로세스에만 SIGTERM을 보내고, 타임아웃 이후 SIGKILL은 cgroup의 모든 프로세스에 보냅니다. 자식 프로세스를 직접 관리하는 애플리케이션에 적합합니다. 각 지시어의 정확한 의미와 기본값은 systemd 버전에 따라 달라질 수 있으니 설치된 버전의 systemd.kill 문서를 확인하세요.
컨테이너도 같은 모델입니다. docker stop은 SIGTERM을 보내고 기본 10초를 기다린 뒤 SIGKILL을 보냅니다. 쿠버네티스는 Pod 스펙의 종료 유예 기간을 씁니다.
docker stop --time 60 mycontainer
kubectl delete pod mypod --grace-period=60
컨테이너에서 자주 겪는 함정이 있습니다. 셸 형식(CMD myapp)으로 실행하면 셸이 PID 1이 되고 애플리케이션은 자식이 됩니다. 이때 SIGTERM은 셸에게 가고, 셸은 그것을 자식에게 전달하지 않습니다. 결과적으로 애플리케이션은 유예 없이 SIGKILL로 죽습니다. exec 형식(CMD ["myapp"])을 쓰거나 적절한 init 프로세스를 넣어야 합니다.
5. PID 1, 좀비, 고아
프로세스가 종료되면 커널은 종료 상태를 남겨 둡니다. 부모가 wait를 호출해 그것을 회수해야 프로세스 항목이 사라집니다. 회수되기 전까지의 상태가 좀비(Z) 입니다.
ps -eo pid,ppid,stat,args | awk '$3 ~ /Z/'
좀비는 메모리를 거의 쓰지 않지만 PID를 점유합니다. 좀비가 수천 개 쌓이면 PID가 고갈되어 새 프로세스를 만들 수 없게 됩니다.
cat /proc/sys/kernel/pid_max
ls /proc | grep -c '^[0-9]'
좀비는 죽일 수 없습니다. 이미 죽었기 때문입니다. 해결책은 부모가 회수하게 만들거나, 부모를 종료시켜 좀비를 PID 1에 입양시키는 것입니다. PID 1은 고아 프로세스를 입양해 자동으로 회수할 책임이 있습니다.
부모가 먼저 죽으면 자식은 고아가 되고 PID 1(또는 서브리퍼로 등록된 프로세스)에 입양됩니다. 좀비가 계속 쌓인다면 부모 프로그램이 SIGCHLD를 처리하지 않는 버그입니다.
컨테이너에서 좀비가 쌓이는 사례가 특히 흔합니다. 애플리케이션이 PID 1로 실행되는데 그 애플리케이션이 자식을 회수하도록 만들어지지 않은 경우입니다. 컨테이너 런타임이 제공하는 init 옵션을 쓰는 것이 표준 해법입니다.
docker run --init myimage
6. 프로세스 그룹, 세션, 그리고 터미널이 닫힐 때
터미널을 닫으면 왜 백그라운드 작업이 죽을까요? 여기에는 세 겹의 구조가 있습니다.
- 프로세스 그룹: 파이프라인 하나가 보통 그룹 하나입니다. 셸의 잡 제어 단위입니다.
- 세션: 로그인 하나가 세션 하나입니다. 세션 리더가 컨트롤 터미널을 가집니다.
- 컨트롤 터미널: 터미널이 사라지면 커널이 세션 리더에게 SIGHUP을 보내고, 세션 리더(대개 셸)는 자신의 잡들에게 SIGHUP을 전파합니다.
현재 구조는 이렇게 봅니다.
ps -eo pid,ppid,pgid,sid,tty,stat,args | head -20
ps -o pid,pgid,sid,tty,args -p $$
터미널이 끊겨도 살아남게 하는 방법은 여러 가지이며 각각 다릅니다.
nohup ./long-job.sh > /var/log/long-job.log 2>&1 &
setsid ./long-job.sh > /var/log/long-job.log 2>&1 &
disown -h %1
systemd-run --user --unit=long-job ./long-job.sh
nohup은 SIGHUP을 무시하도록 설정하고 실행합니다. 여전히 같은 세션에 속합니다.setsid는 새 세션을 만들어 컨트롤 터미널과의 관계 자체를 끊습니다. 더 확실합니다.disown -h는 이미 실행 중인 잡을 셸의 SIGHUP 전파 대상에서 제외합니다.systemd-run은 아예 별도 유닛으로 실행해 세션과 무관하게 만듭니다. 운영 서버에서 장시간 작업을 돌릴 때 가장 안전한 선택입니다.
SSH 세션에서 긴 작업을 돌린다면 tmux나 screen을 쓰는 것이 실용적입니다. 연결이 끊겨도 세션이 유지되고 나중에 다시 붙을 수 있습니다.
7. 애플리케이션에서 시그널 다루기
셸 스크립트에서는 trap으로 처리합니다.
#!/usr/bin/env bash
set -euo pipefail
cleanup() {
echo "cleaning up..."
rm -f /tmp/myjob.lock
}
trap cleanup EXIT
trap 'echo "received SIGTERM"; exit 143' TERM
trap 'echo "received SIGINT"; exit 130' INT
while true; do
sleep 1
done
trap ... EXIT은 어떤 경로로 종료되든 실행되므로 정리 로직을 넣기에 적합합니다. 종료 코드 관례는 128 더하기 시그널 번호입니다. SIGTERM(15)으로 죽으면 143, SIGINT(2)면 130입니다. 이 관례를 알면 systemctl status나 CI 로그에서 143을 보고 "정상적인 종료 요청을 받았구나"라고 바로 읽을 수 있습니다.
주의할 점은 sleep 같은 외부 명령을 실행하는 동안에는 bash가 트랩을 즉시 처리하지 않고 해당 명령이 끝난 뒤에 처리한다는 것입니다. 긴 sleep을 쓰면 반응이 느려집니다. 백그라운드로 돌리고 wait를 쓰면 즉시 반응합니다.
sleep 300 &
wait $!
timeout 명령도 유용합니다.
timeout 30 ./maybe-hangs.sh
timeout -s KILL 30 ./maybe-hangs.sh
timeout -k 10 30 ./maybe-hangs.sh
-k는 먼저 기본 시그널을 보내고, 지정한 시간이 더 지나도 살아 있으면 SIGKILL을 보냅니다. 앞서 만든 두 단계 종료 스크립트를 한 줄로 대체할 수 있습니다.
8. 죽지 않는 프로세스를 계층별로 추적하기
"안 죽는다"는 신고를 받으면 다음 순서로 좁힙니다.
1단계 — 정말 살아 있는가. 좀비라면 이미 죽은 것입니다.
ps -o pid,ppid,stat,args -p 1234
2단계 — 시그널이 전달되었는가. 권한 문제로 전달 자체가 실패했을 수 있습니다.
kill -0 1234; echo "exit=$?"
Operation not permitted가 나오면 권한 문제입니다.
3단계 — 프로세스가 시그널을 잡고 있는가.
grep -E '^SigIgn|^SigCgt|^SigBlk' /proc/1234/status
4단계 — D 상태인가. 이 경우 시그널은 아무 소용이 없습니다.
cat /proc/1234/status | grep '^State'
sudo cat /proc/1234/stack
스택에 NFS나 블록 계층 함수가 보이면 스토리지가 응답할 때까지 기다려야 합니다. 마운트가 끊긴 NFS라면 강제 언마운트가 유일한 탈출구입니다.
sudo umount -f -l /mnt/nfsshare
파괴적 명령 경고: umount -l(lazy)은 마운트를 네임스페이스에서 즉시 분리하되 사용 중인 참조는 남겨 둡니다. 진행 중이던 쓰기가 유실될 수 있으므로 마지막 수단으로만 쓰세요.
5단계 — 재기동 후에도 반복되는가. 그렇다면 시그널 문제가 아니라 애플리케이션이나 스토리지의 구조적 문제입니다.
9. 우선순위와 자원 한도
프로세스를 죽이는 대신 억제하는 방법도 있습니다.
nice -n 10 ./batch-job.sh
renice -n 10 -p 1234
ionice -c 3 -p 1234
chrt -p 1234
nice값은 -20(가장 높은 우선순위)에서 19(가장 낮음)까지입니다. 음수로 낮추려면 root 권한이 필요합니다.ionice -c 3은 유휴 I/O 클래스로, 다른 프로세스가 디스크를 쓰지 않을 때만 I/O를 수행합니다. 야간 백업이나 대용량 복사 작업에 걸어 두면 운영 트래픽에 주는 영향이 크게 줄어듭니다.chrt는 실시간 스케줄링 정책을 다룹니다. 잘못 쓰면 시스템을 응답 불가 상태로 만들 수 있으므로 신중해야 합니다.
한도는 ulimit과 systemd 지시어로 겁니다.
ulimit -a
ulimit -n
cat /proc/1234/limits
systemd 유닛에서는 다음과 같이 설정합니다.
[Service]
LimitNOFILE=65535
LimitNPROC=4096
MemoryMax=2G
CPUQuota=200%
MemoryMax를 넘으면 cgroup OOM 킬러가 그 서비스 안에서만 프로세스를 죽입니다. 시스템 전체 OOM으로 번지는 것을 막아 주므로, 메모리를 많이 쓰는 서비스에는 반드시 걸어 두는 편이 좋습니다. 사용 가능한 지시어와 기본값은 systemd 버전마다 다르므로 설치된 버전의 systemd.resource-control 문서를 확인하세요.
퀴즈: 실력을 확인해 보세요
퀴즈 1: kill -9를 보냈는데 프로세스가 목록에 그대로 남아 있습니다. 무엇을 먼저 확인하나요?
정답: 프로세스 상태가 Z(좀비)인지 D(중단 불가 대기)인지 확인합니다
설명: 두 상태는 원인도 대응도 완전히 다릅니다.
ps -o pid,ppid,stat,wchan:24,args -p 1234
Z라면 이미 죽었고 부모가 회수하지 않은 것이므로, 죽일 대상이 없습니다. 부모 프로세스를 처리해야 사라집니다. D라면 커널이 I/O 완료를 기다리는 중이며 SIGKILL도 즉시 전달되지 않습니다. 기다리는 자원을 복구해야 합니다.
sudo cat /proc/1234/stack
퀴즈 2: 컨테이너를 정지시켰는데 애플리케이션이 종료 처리를 실행하지 못하고 즉시 끊깁니다. 원인 후보는?
정답: 셸이 PID 1이 되어 SIGTERM을 자식에게 전달하지 않는 경우가 대표적입니다
설명: Dockerfile에서 셸 형식으로 명령을 지정하면 /bin/sh -c 아래에서 애플리케이션이 실행됩니다. 런타임이 보내는 SIGTERM은 PID 1인 셸이 받고, 셸은 그것을 전달하지 않습니다. 유예 시간이 지나면 SIGKILL이 cgroup 전체에 적용되어 애플리케이션은 아무 정리도 못 하고 죽습니다. exec 형식으로 바꾸거나 init 프로세스를 넣어야 합니다.
docker run --init myimage
docker stop --time 60 mycontainer
애플리케이션이 실제로 SIGTERM 핸들러를 등록했는지도 확인하세요.
grep SigCgt /proc/1/status
퀴즈 3: SSH로 접속해 배포 스크립트를 실행하다 연결이 끊겼습니다. 스크립트가 중단되지 않게 하려면 무엇을 썼어야 할까요?
정답: setsid, systemd-run, tmux 중 하나로 세션에서 분리해 실행했어야 합니다
설명: 터미널이 사라지면 커널이 세션 리더에게 SIGHUP을 보내고 셸이 그것을 잡들에게 전파합니다. nohup은 SIGHUP을 무시하게 만들지만 여전히 같은 세션에 속합니다. 더 확실한 것은 새 세션을 만드는 방법입니다.
setsid ./deploy.sh > /var/log/deploy.log 2>&1 &
systemd-run --unit=deploy-2026-08-15 ./deploy.sh
tmux new -s deploy
운영 서버라면 systemd-run이 가장 낫습니다. 로그가 저널에 남고 상태를 systemctl status로 조회할 수 있기 때문입니다.
퀴즈 4: 좀비 프로세스가 시간이 갈수록 늘어납니다. 어떤 실제 위험이 있고 무엇을 고쳐야 하나요?
정답: PID 고갈 위험이 있으며, 부모 프로그램이 자식을 회수하지 않는 것이 원인입니다
설명: 좀비는 메모리를 거의 쓰지 않지만 PID 슬롯을 점유합니다. pid_max에 도달하면 새 프로세스를 전혀 만들 수 없어 시스템이 사실상 정지합니다.
ps -eo pid,ppid,stat,args | awk '$3 ~ /Z/' | head
cat /proc/sys/kernel/pid_max
부모 PID를 확인해 그 프로그램이 자식 종료를 처리하도록 고치는 것이 근본 해결입니다. 임시 조치로 부모를 재기동하면 좀비들이 PID 1에 입양되어 회수됩니다.
퀴즈 5: 셸 스크립트에 SIGTERM 트랩을 걸었는데 반응이 10초씩 늦습니다. 왜일까요?
정답: 외부 명령이 실행 중일 때 bash는 그 명령이 끝난 뒤에 트랩을 처리하기 때문입니다
설명: sleep 10이 실행되는 동안 시그널이 도착하면, bash는 sleep이 반환된 뒤에 트랩 핸들러를 실행합니다. 즉시 반응하게 하려면 백그라운드로 돌리고 wait를 씁니다.
sleep 10 &
wait $!
wait는 시그널이 오면 즉시 반환되므로 트랩이 바로 실행됩니다. 종료 코드 관례도 함께 기억하세요. SIGTERM으로 종료하면 143, SIGINT면 130입니다.
퀴즈 6: 야간 배치가 운영 트래픽의 응답 시간을 망칩니다. 배치를 죽이지 않고 완화하려면?
정답: nice로 CPU 우선순위를, ionice로 I/O 우선순위를 낮춥니다
설명: 배치 작업은 늦게 끝나도 되지만 운영 요청은 그렇지 않습니다. 우선순위를 낮추면 자원이 남을 때만 배치가 진행됩니다.
renice -n 19 -p 1234
sudo ionice -c 3 -p 1234
ionice -c 3은 유휴 클래스로, 다른 프로세스가 디스크를 쓰지 않을 때만 I/O를 수행합니다. 근본적으로는 systemd 유닛에서 자원 제어를 걸어 두는 편이 좋습니다.
[Service]
Nice=19
IOSchedulingClass=idle
CPUQuota=50%
마치며
시그널은 단순해 보이지만 프로세스 그룹, 세션, 컨트롤 터미널, cgroup, 컨테이너 런타임이 겹겹이 얹혀 있습니다. 그래서 "왜 안 죽는가"라는 질문의 답이 매번 다른 계층에서 나옵니다.
실무에서 기억할 것은 세 가지입니다. SIGKILL과 SIGSTOP만 절대적이고 나머지는 애플리케이션이 마음대로 할 수 있다. D 상태에서는 어떤 시그널도 소용없으므로 스토리지를 봐야 한다. 종료는 항상 SIGTERM과 유예 시간으로 시작하고 SIGKILL은 마지막 수단이다.
마지막 문장은 특히 데이터를 다루는 서비스에서 중요합니다. 종료 유예 시간을 10초로 두고 운영하다가 대량 트랜잭션 중에 SIGKILL이 나가면, 그날의 장애는 종료 절차가 만든 것입니다.
참고 자료
- signal(7) — man7.org (2026-08-15 확인)
- proc_pid_fd(5) — man7.org (2026-08-15 확인)
- dmesg(1) — man7.org (2026-08-15 확인)
- systemd 공식 문서 — freedesktop.org (2026-08-15 확인)
이어서 읽기
- 이전 글: 리눅스 성능 도구 완전 가이드
- 다음 글: SSH 운영 완전 가이드
- systemd 서비스 관리 완벽 가이드 — 유닛 파일로 종료 절차를 설계하기
- 터미널과 셸 내부 완전 가이드 — PTY와 잡 제어의 내부 동작
- Linux 터미널 — 시그널 관련 명령 연습
- 리눅스 명령어 퀴즈 — 옵션 기억 점검