Tomcat 재시작 전 프로세스 종료 확인
Tomcat이 실행 중이면 종료 후 다시 시작하고, 꺼져 있으면 시작하는 Bash 스크립트를 작성했던 기록입니다. 종료 명령을 보낸 뒤에도 프로세스가 남을 수 있어, 다음 시작 전에 상태를 확인하는 코드를 넣었습니다.
한 장비에서 Tomcat을 여러 개 실행할 수 있다는 점도 고려해야 했습니다. 단순히 Java 프로세스를 찾으면 다른 인스턴스까지 종료할 수 있기 때문입니다.
당시 스크립트의 실행 순서
실제 코드의 흐름은 다음과 같았습니다.
- 대상 프로세스가 있으면
shutdown.sh를 실행합니다. - 잠시 기다리며 종료 여부를 반복 확인합니다.
- 계속 남아 있으면
SIGTERM을 보내고 다시 확인합니다. - 그래도 남아 있으면
SIGKILL을 사용합니다. - 종료 처리 뒤
startup.sh를 실행합니다.
원문 주석에는 SIGTERM을 다섯 번 시도한다고 적혀 있었지만, 실제 코드는 신호 없이 기다리는 루프가 다섯 번이고 SIGTERM 루프는 두 번이었습니다. 설명과 코드의 동작부터 맞춰 볼 필요가 있었습니다.
SIGKILL 단계는 정상 종료가 아닙니다. 애플리케이션이 연결을 닫거나 후처리할 기회 없이 프로세스를 끝내므로, 종료를 기다리는 단계와 구분해야 합니다.
대상 인스턴스 식별
당시에는 Bootstrap 클래스 이름과 인스턴스 경로가 포함된 문자열을 조합했습니다.
ps aux \
| grep org.apache.catalina.startup.Bootstrap \
| grep /web \
| grep -v grep \
| awk '{ print $2 }'/web은 당시 환경의 구분 값입니다. 이 문자열이 다른 인스턴스에도 들어 있으면 PID가 여러 개 나올 수 있고, 경로가 바뀌면 찾지 못할 수도 있습니다. 이 결과를 숫자 하나라고 가정해 종료 명령에 넘기는 방식에는 한계가 있습니다.
Tomcat을 시작할 때 인스턴스별 CATALINA_PID를 지정했다면 PID 파일을 기준으로 관리할 수 있습니다. 단, 시작과 종료에서 같은 설정을 사용해야 하고, 오래된 PID 파일이나 PID 재사용 가능성도 확인해야 합니다.
종료 실패와 재시작 분리
기존 스크립트는 마지막 신호를 보낸 뒤 PID를 다시 읽지 않는 구간이 있었고, stop의 성공 여부를 확실히 판정하지 않은 채 start로 넘어갈 수 있었습니다. startup.sh 뒤에 잠깐 기다리고 PID를 출력하는 것만으로 애플리케이션이 준비됐다고 볼 수도 없었습니다.
이 부분은 세 단계로 나누는 편이 명확합니다. 종료 실패 시에는 새 프로세스를 시작하지 않고, 시작 명령의 성공 뒤에는 프로세스 상태를 확인하며, 마지막으로 애플리케이션의 응답을 확인합니다.
현재 Tomcat 스크립트를 사용할 때는 직접 신호 처리 코드를 늘리기 전에 기본 기능도 확인할 수 있습니다. 예를 들어 Tomcat 9.0.99의 catalina.sh에는 PID 파일과 대기 시간, 강제 종료 옵션을 처리하는 코드가 있습니다.
# 같은 인스턴스의 CATALINA_HOME, CATALINA_BASE, CATALINA_PID 설정 필요
"$CATALINA_HOME/bin/catalina.sh" stop 20 -force이 명령은 2018년에 작성한 스크립트 자체가 아니라, 공식 스크립트의 기능을 비교하기 위한 예입니다. 서비스 관리자나 별도 관리 도구로 실행 중이라면 그 도구의 종료 절차를 따라야 합니다.
프로세스 종료와 서비스 가용성
응답이 없거나 종료되지 않는 프로세스를 모두 “좀비 프로세스”라고 부를 수는 없습니다. 좀비는 이미 실행을 마쳤지만 부모가 종료 상태를 회수하지 않은 상태를 가리킵니다.
이 스크립트가 다룬 것은 종료 명령 뒤의 프로세스 확인입니다. 인스턴스를 종료하고 다시 시작하는 동안 서비스 요청을 어디서 처리할지는 별도 문제입니다. 트래픽을 다른 인스턴스로 넘기거나 처리 중인 요청을 기다리는 구성 없이, 재시작 스크립트만으로 무중단 배포가 되지는 않습니다.