http://en.wikipedia.org/wiki/Kill_(command)

 

kill 은 리눅스를 많이 사용하지 않은 독자라도 거의 대부분이 아는 명령어로 용도는 특정 이벤트가 발생했음을 프로세스에게 알리는 것이다.  시그널은 숫자 값으로 정의되어 있으며 숫자는 기억하기가 어려우므로 의미있는 이름도 부여되어 있다.

최초 시그널 번호는 1로 시작하고 있으며 1번 시그널은 터미널과 프로세스의 연결이 끊겼음을 의미하는 SIGHUP(Hang Up) 이다.

시그널의 숫자와 의미는 유닉스의 표준중 하나인 POSIX(Portable Operating System Interface) 에 정의되어 있다.


개발자는 프로그램을 만들 때 특정 시그널을 수신했을 때 처리 로직(시그널 핸들러)을 작성할 수 있으며 이를 이용해 수신한 시그널의 종류에 다르게 동작하게 할 수 있다.

시그널 핸들러를 특별히 지정하지 않았을 경우 기본 정의된 액션이 동작하며 이는 시그널의 종류에 따라 다르다. 기본 정의된 액션은 다음 표처럼 총 5가지 이다.

액션명동작
TERM시그널을 수신한 프로세스 종료
IGN시그널 무시
CORE시그널을 수신한 프로세스를 종료하면서 코어 덤프(core dump) 파일 생성
STOP시그널을 수신한 프로세스 정지
CONT중지된 프로세스 재시작
기본 시그널 액션

일반적인 유닉스 프로그램들은 TERM(15) 이나 INT(2) 시그널을 수신하면 프로그램이 사용하는 자원이나 객체를 반납하고 메모리를 정리하고 종료하도록 구현하고 있지만 개발자의 의도에 따라 시그널을 무시하거나 특정 기능을 수행하도록 작성 할 수도 있다.

시그널 중에 두 개의 시그널(KILL(9), STOP(23))은 프로그램이 무시하거나 별도의 처리 로직을 수행할 수 없고 바로 프로그램이 종료된다.

프로세스에 시그널을 전송하는 kill 명령어의 사용법은 다음과 같다.

kill -signum pid    

signum 옵션은 SIGHUP 같은 시그널 명에서 SIG 접두사를 떼고 사용하거나(대소문자를 구분하지 않는다.) 숫자 1 처럼 바로 시그널 번호를 쓰는 두 가지 방식으로 사용할 수 있다. 다음 두 명령어는 명령어는 동일한 의미이다.

## pid 1234 프로세스에 hang up 시그널 전송
kill -1 1234
kill -hup 1234
 
## pid 1234 프로세스에 kill 시그널 전송
kill -9 1234
kill -kill 1234

signum 옵션은 생략할 수 있으며 생략시 TERM(Terminate) 시그널을 전송하게 되며 프로그램이 별도의 시그널 핸들러를 만들지 않았을 경우 기본 시그널 핸들러인 "프로세스 종료" 기능이 수행된다. 

이제 왜 시그널 전송 명령어 이름이 kill 인지 이유를 짐작할 수 있을 것이다. 기본 시그널이 TERM 시그널이며 프로세스가 이 시그널을 수신시 기본 동작이 프로세스 종료라서 kill 이 되었다지만 다른 동작도 가능하므로 명령어 이름을 잘못 지은 셈이다.

 

본 절에서 kill 명령어를 다루는 이유는 서비스 프로그램을 종료할 때 한 번에 종료한다는 이유로 kill -9 로 프로세스를 종료하는 경우를 많이 보아서 이다.

 

리눅스를 포함하여 유닉스는 프로그램 작성시 시그널 핸들러를 등록할 수 있으므로 잘 만든 유닉스 프로그램이라면 INT, TERM 시그널을 받으면 사용하는 자원이나 객체를 반납하고 메모리를 정리하고 종료하도록 구현되어 있다.

시그널중에는 핸들러를 지정할 수 없는 시그널이 두 개 있으며 바로 KILL(9), STOP(19) 두 개의 시그널이다.

그러므로 프로세스가 이 시그널을 받으면 내부의 자원 반납과 정리 루틴을 호출하지 못하고 바로 종료되어 버릴 수 있으므로 TERM이나 INT 로는 종료되지 않는 프로세스외에는 일반적으로 사용하지 않는 게 좋다.

 

kill 명령어로 프로세스를 안전하게 종료 시키기 위해 권장하는 방법은 먼저 kill -TERM PIDkill -INT PID 같이 TERM(Termination) 나 INT(Interrupt) 시그널을 전송하는 것이다.

Java VM 도 TERM 시그널을 수신할 경우 깨끗하게 종료되니 tomcat 이나 기타 java VM 위에서 돌아가는 프로그램 종료시 KILL 시그널을 바로 보내지 말고 두 세 번 정도 TERM(15) 시그널을 보내고 그래도 종료가 되지 않을 경우 KILL 시그널을 전송하는게 좋다.

Linux에서 서비스 프로세스를 관리하는 service 명령어도 TERM 시그널을 보낸후에 일정 시간후에도 프로세스가 종료되지 않았으면 KILL 시그널을 보내게 구현되어 있다.

 

프로세스가 포크(fork) 하여 여러 개의 자식 프로세스를 갖고 있을 경우 이를 한 번에 종료시키려면 스크립트를 이용하여 프로세스의 PID 를 모두 얻은 후에 파이프를 이용하여 awk 로 명령어를 구성해서 종료할 수 있다.

ps -eaf PROCESS_NAME|grep -v grep|awk '{print "kill -TERM "$2}' | sh -x

 

만약에 httpd 프로세스를 모두 종료할 경우 다음과 같이 수행하면 된다.

 

ps -eaf httpd|grep -v grep|awk '{print "kill -TERM "$2}' | sh -x

위의 script 를 두 세 번 실행해 보고 종료가 되지 않는 process 가 있다면 SIGTERM 대신 SIGKILL 을 사용하면 조금 더 안전하게 프로세스를 종료 시킬 수 있다.

책의 뒷 부분 톰캣 부분에서는 위 스크립트를 확장하여 톰캣을 깔끔하게 종료시키는 스크립트를 작성하고 지속적인 통합에 연계할 것이다.