PRO DBDATA PRO DBDATA

systemd 서비스가 반복 재시작되는 원인: Type=notify·WatchdogSec·시작 제한 분석 가이드

읽는 시간 약 16분
systemd 서비스가 반복 재시작되는 원인

Linux 서버에서 서비스 프로세스가 잠깐 실행됐다가 종료되는 현상이 반복되면 애플리케이션 오류부터 의심하기 쉽습니다. 하지만 systemd가 시작 완료 알림을 받지 못하거나, 실행 중 생존 알림이 끊겨 프로세스를 종료하는 경우도 있습니다.

이러한 장애는 CPU와 메모리 사용률만으로 구분하기 어렵습니다. 모니터링 수집 순간에는 프로세스가 살아 있어 정상으로 보이지만, 실제로는 초기화와 종료를 반복하면서 요청을 처리하지 못할 수 있습니다.

재시작이 이어지면 데이터베이스 연결과 캐시 초기화까지 반복됩니다. 이때 연결 수 증가나 응답 지연은 최초 원인이 아니라 서비스 재시작이 만든 후속 증상일 가능성도 있습니다.

원인을 찾으려면 프로세스 실행, 서비스 준비 완료, 실행 중 상태 감시, 시작 횟수 제한을 나누어 살펴봐야 합니다. 각각의 동작 원리와 로그를 연결하면 무작정 타임아웃을 늘리지 않고도 복구 방향을 정할 수 있습니다.

장애 증상과 초기 판단

대표적인 증상은 서비스 상태가 activating, failed, auto-restart 사이에서 바뀌거나 PID가 계속 달라지는 것입니다. 잠깐 정상 응답을 보낸 뒤 연결이 끊어지기도 하고, 시작 제한에 걸려 재시작마저 멈추기도 합니다.

다음은 원인별로 나타날 수 있는 서로 다른 로그 예시입니다. 실제 문구와 부가 정보는 systemd 버전에 따라 달라질 수 있습니다.

app.service: start operation timed out. Terminating.
app.service: Failed with result 'timeout'.

app.service: Watchdog timeout (limit 30s)!
app.service: Failed with result 'watchdog'.

app.service: Start request repeated too quickly.
app.service: Failed with result 'start-limit-hit'.

첫 번째는 시작 작업이 제한 시간 안에 끝나지 않은 상황입니다. Type=notify라면 준비 완료 알림 누락을 의심할 수 있지만, 시작 전후 명령의 지연도 확인해야 합니다.

두 번째는 실행 중 Watchdog 감시 조건을 만족하지 못한 상황입니다. 시작 지연과는 조사해야 할 시점이 다릅니다.

세 번째는 일정 시간 안에 시작 시도가 집중되어 추가 시작이 차단된 결과입니다. start-limit-hit 앞에 기록된 최초 실패가 무엇인지 확인하는 것이 핵심입니다.

예를 들어 설정 파일 경로 오류로 실행 직후 종료되는 서비스는 재시작을 반복하다 시작 제한에 도달할 수 있습니다. 이때 제한만 풀면 같은 오류가 다시 발생합니다.

내부 동작 원리와 장애 발생 구조

프로세스 실행과 준비 완료는 다릅니다

프로세스가 생성됐다고 데이터베이스 연결, 설정 로딩, 캐시 준비까지 끝난 것은 아닙니다.

Type=notify에서는 애플리케이션이 READY=1을 보내야 systemd가 준비 완료를 인식합니다. 알림을 지원하지 않는 프로그램에 설정만 추가하면 시작 완료를 기다리다 실패할 수 있습니다. 서비스 유형의 의미는 Debian 공식 배포 문서의 systemd.service 설명에서 확인할 수 있습니다.

알림을 보냈는데도 인식되지 않는다면 전송 주체를 살펴봐야 합니다. NotifyAccess=main인 서비스에서 별도 자식 프로세스가 알림을 보내면 허용 범위와 맞지 않을 수 있습니다. 실행 스크립트가 실제 서버를 자식으로 띄우는지도 확인할 대상입니다.

알림 수신 범위와 전송 프로세스의 수명에 따른 주의점은 systemd 공식 sd_notify 문서에 설명되어 있습니다.

시작 타임아웃과 Watchdog는 감시 구간이 다릅니다

TimeoutStartSec는 시작 단계의 시간 제한입니다. 반면 WatchdogSec는 시작 완료 후 주기적인 WATCHDOG=1 알림을 요구하는 실행 중 감시 설정입니다.

예를 들어 준비 완료 알림이 오지 않아 시작이 실패했다면 WatchdogSec를 늘려도 해결되지 않습니다. 반대로 정상 기동 후 알림 전송이 멈췄다면 초기화 시간보다 이벤트 루프 정체와 알림 구현을 조사해야 합니다.

Watchdog는 systemd가 HTTP 주소에 접속해 확인하는 기능이 아닙니다. 애플리케이션의 알림 구현이 필요하며, 해당 알림이 실제 요청 처리 상태를 얼마나 반영하는지도 중요합니다.

재시작 정책과 시작 제한은 별개입니다

Restart는 종료 후 자동 재시작 조건을, RestartSec는 재시작 전 대기 시간을 정합니다.

StartLimitIntervalSecStartLimitBurst는 지정 구간의 시작 횟수를 제한합니다. 자동 재시작뿐 아니라 수동 시작도 제한 대상이 될 수 있으며, 제한 시간이 지났다고 중단된 자동 재시작이 저절로 재개되는 것은 아닙니다. 관련 조건은 Debian 공식 systemd.unit 문서에 정리되어 있습니다.

재시작 간격이 짧으면 초기화 과정의 데이터베이스 접속과 인증 요청이 집중될 수 있습니다. 따라서 재시작 정책은 복구 속도뿐 아니라 의존 시스템에 가해지는 부하까지 고려해야 합니다.

확인 지표와 진단 명령어

아래 명령은 시스템 서비스 app.service를 대상으로 합니다. 실제 서비스 이름으로 바꾸어 사용하며, 출력은 설명을 위한 예시입니다. 배포판별 차이는 해당 서버의 매뉴얼과 실제 조회 결과를 우선합니다.

현재 상태와 자동 재시작 횟수 확인

systemctl show app.service \
  -p ActiveState -p SubState -p Result \
  -p MainPID -p NRestarts
MainPID=0
Result=watchdog
NRestarts=7
ActiveState=activating
SubState=auto-restart

이 예시는 Watchdog 실패 후 자동 재시작을 기다리는 순간입니다. MainPID=0은 조회 시점에 주 프로세스가 없다는 뜻이며, 실행 파일이 없다는 의미는 아닙니다.

NRestarts는 자동 재시작 횟수입니다. 값이 7이라는 사실보다 같은 관찰 구간에서 계속 증가하는지가 중요합니다. 예를 들어 1분 뒤 10으로 증가했다면 그동안 자동 재시작이 이어진 것입니다.

이 값은 영구 누적 지표가 아니며 초기화될 수 있습니다. 또한 재기동 과정에서 상태가 바뀌므로 Result 하나로 전체 장애 이력을 판단하지 않습니다.

실제 적용된 정책 확인

systemctl show app.service \
  -p Type -p NotifyAccess \
  -p TimeoutStartUSec -p WatchdogUSec \
  -p Restart -p RestartUSec \
  -p StartLimitIntervalUSec -p StartLimitBurst
Type=notify
Restart=on-failure
NotifyAccess=main
RestartUSec=5s
TimeoutStartUSec=1min 30s
WatchdogUSec=30s
StartLimitIntervalUSec=1min
StartLimitBurst=5

이 예시에서는 시작 제한 시간이 90초이고, 실행 중 Watchdog 제한은 30초입니다. 실패 시 5초를 기다린 뒤 재시작하며, 1분 구간의 시작 허용 횟수는 5회입니다. 이는 기본값이 아니라 예시 환경의 적용값입니다.

속성 이름에 USec가 포함되어 있어도 출력은 30s처럼 읽기 쉬운 단위로 표시될 수 있습니다.

또한 이 조합에서 모든 장애가 반드시 시작 제한에 걸리는 것은 아닙니다. 매번 시작 실패까지 90초가 걸린다면, 실행 직후 종료되는 경우보다 시작 시도가 훨씬 드물기 때문입니다.

최초 실패부터 시간순으로 로그 확인

sudo journalctl -u app.service -b \
  --since "20 minutes ago" \
  -o short-iso --no-pager
2026-09-05T12:00:00+0000 host systemd[1]: Starting app.service - Example API...
2026-09-05T12:00:01+0000 host app[4210]: Connecting to database
2026-09-05T12:01:30+0000 host systemd[1]: app.service: start operation timed out. Terminating.
2026-09-05T12:01:30+0000 host systemd[1]: app.service: Failed with result 'timeout'.

これは 앞선 Watchdog 상태와는 별개의 시작 실패 예시입니다. 시작 후 90초에 타임아웃이 발생했고, 애플리케이션의 마지막 메시지는 데이터베이스 연결 단계입니다.

이 로그만으로 데이터베이스 장애를 확정할 수는 없습니다. DNS 조회, 네트워크 연결, 인증 대기, 연결 재시도, 준비 알림 누락을 추가로 구분해야 합니다.

운영 판단에서 우선할 것은 가장 마지막 오류보다 가장 먼저 진행이 멈춘 단계입니다. CPU가 낮더라도 네트워크 응답이나 잠금을 기다리고 있을 수 있어, 자원 사용률만 보고 서버를 증설하면 원인을 놓칠 수 있습니다.

원본 유닛과 추가 설정 확인

systemctl cat app.service
# /etc/systemd/system/app.service
[Unit]
Description=Example API

[Service]
Type=notify
ExecStart=/opt/app/bin/server
NotifyAccess=main
Restart=on-failure

# /etc/systemd/system/app.service.d/override.conf
[Service]
TimeoutStartSec=90s
WatchdogSec=30s
RestartSec=5s

원본 파일과 추가 설정인 drop-in을 함께 확인합니다. 패키지 기본 설정만 살펴보면 이전 장애 대응 때 추가한 변경을 놓칠 수 있습니다.

systemctl cat은 디스크의 설정을 보여주므로, 파일을 수정하고 아직 다시 읽지 않은 상태에서는 앞서 조회한 적용값과 다를 수 있습니다.

원인별 복구 절차와 해결 방법

반복 재시작의 영향을 먼저 줄이기

복제 인스턴스가 있다면 문제 인스턴스로 들어오는 트래픽을 먼저 제외합니다. 재시작이 데이터베이스 연결 폭증을 유발한다면 로그와 현재 상태를 확보한 뒤 서비스를 일시 중지하는 방안을 검토합니다.

sudo systemctl stop app.service
성공 시 일반적으로 별도 출력 없음

명시적인 중지는 Restart 정책에 따른 자동 재시작을 유발하지 않습니다. 다만 타이머, 소켓 활성화, 외부 배포 도구가 별도로 시작시키는지는 확인해야 합니다.

단일 인스턴스라면 중지가 곧 서비스 중단이므로 우회 경로나 복구 순서를 먼저 정합니다.

준비 완료 알림이 누락된 경우

애플리케이션이 systemd 알림을 실제로 지원하는지 확인합니다. 지원한다면 초기화 완료 시점에 READY=1을 전송하는지, 전송 주체가 NotifyAccess와 맞는지 점검합니다.

NotifyAccess=all로 무조건 넓히기보다 주 프로세스 식별과 실행 스크립트 구조를 먼저 바로잡는 편이 좋습니다.

알림 미지원 프로그램은 실행 방식에 맞는 서비스 유형을 선택해야 합니다. 다만 Type=simple이나 Type=exec로 바꾸면 애플리케이션 준비 완료를 기다리던 의미가 달라집니다. 별도 readiness 검사와 의존 서비스의 시작 조건도 함께 검토해야 합니다.

정상 초기화가 시작 제한 시간을 초과하는 경우

정상 초기화 시간의 분포를 측정하고 제한 시간을 조정합니다. 예를 들어 대용량 캐시 로딩 때문에 기동 시간이 길어졌다면 로딩 구간과 데이터 규모를 함께 비교합니다.

데이터베이스 연결을 무한 재시도하는 상태라면 시간 연장은 실패 확인만 늦춥니다. 연결별 타임아웃, 재시도 상한, 초기화 단계별 로그를 개선하는 것이 근본적인 해결책입니다.

다음은 테스트 환경에서 검증할 drop-in 설정 내용 예시입니다. 범용 권장값이 아니며, 기존 설정을 백업하고 변경 관리 절차에 따라 적용해야 합니다.

[Unit]
StartLimitIntervalSec=300s
StartLimitBurst=5

[Service]
TimeoutStartSec=120s
RestartSec=15s

일시 검증용 drop-in은 /run/systemd/system/app.service.d/ 아래에 두고, 검증 후 영구 설정은 /etc/systemd/system/app.service.d/ 아래에서 관리합니다. 같은 항목을 덮어쓰는 다른 파일이 있는지 확인하고 실제 적용값을 다시 조회합니다.

Watchdog 실패가 발생한 경우

알림 전송이 구현되어 있는지부터 확인합니다. 구현되어 있다면 실패 직전의 이벤트 루프 지연, GC 정지, 잠금 대기, CPU 제한 등을 같은 시간축으로 조사합니다.

예를 들어 제한이 30초인데 알림도 30초 간격으로 보내면 작은 스케줄링 지연에도 실패할 수 있습니다. 충분한 여유를 두어야 하며, 알림 전용 스레드만 살아 있고 실제 처리 스레드는 멈춘 상황을 정상으로 보고하지 않도록 설계해야 합니다.

Watchdog 시간을 늘리는 것은 허용 지연을 바꾸는 조치입니다. 교착 상태나 장시간 블로킹을 해결하는 조치와는 구분해야 합니다.

원인을 수정한 뒤 시작 제한 해제

설정 변경 후 다음 순서로 다시 읽고, 실패 상태를 초기화한 뒤 시작할 수 있습니다.

sudo systemctl daemon-reload
sudo systemctl reset-failed app.service
sudo systemctl start app.service
각 명령이 성공하면 일반적으로 별도 출력 없음

실패한 명령이 있으면 다음 단계로 진행하기 전에 해당 오류를 확인합니다.

daemon-reload는 유닛 정의를 다시 읽는 작업이며 실행 중 애플리케이션 자체를 재시작하지 않습니다. 위 예시는 서비스를 중지했거나 실패한 상태를 전제로 합니다.

reset-failed는 실패 상태와 시작 제한 카운터 등을 초기화하지만 애플리케이션 오류를 수정하지는 않습니다. 세부 동작은 Debian 공식 systemctl 문서에서 확인할 수 있습니다.

변경 후에는 최소한 NRestarts 증가 여부와 실제 요청 성공률을 함께 비교해야 합니다. active 표시만 확인하고 종료하면 준비 알림 이후 발생하는 장애를 놓칠 수 있습니다.

재발 방지와 마치며

모니터링에는 프로세스 존재 여부 외에 자동 재시작 횟수 변화, activating 지속 시간, Watchdog 실패 로그, 실제 응답 성공률을 포함합니다.

예를 들어 평소 재시작이 없는 서비스라면 짧은 구간의 재시작 발생 자체를 조사 대상으로 삼을 수 있습니다. 배포 시 정상 재기동과 장애 재기동을 구분하도록 배포 이력도 연결합니다.

시작 제한 시간은 평상시 평균보다 느린 기동 구간을 기준으로 검토하고, Watchdog 기준은 허용 가능한 처리 정지 시간과 알림 지연을 함께 고려합니다. 부하 테스트에는 데이터베이스 응답 지연과 캐시가 비어 있는 기동 조건도 포함하는 것이 좋습니다.

배포 전에는 알림 지원 여부, 주 프로세스 식별, 시작 시간 분포, 재시작 간격, 시작 제한, 요청 기반 상태 검사를 점검합니다.

systemd 반복 재시작의 진단 기준은 어느 단계에서 실패했고 누가 종료를 결정했는가입니다. 시작 전후의 타임아웃과 실행 중 Watchdog를 구분하고, 시작 제한 이전의 로그까지 확인해야 같은 장애의 반복을 막을 수 있습니다.

PRODB

함께 보면 좋은 글

댓글 0

첫 댓글을 남겨보세요.

error: Content is protected !!

광고 차단 알림

광고 클릭 제한을 초과하여 광고가 차단되었습니다.

단시간에 반복적인 광고 클릭은 시스템에 의해 감지되며, IP가 수집되어 사이트 관리자가 확인 가능합니다.