프로그래밍/운영체제

systemd Type=notify 기준 정리

포도알77 2026. 6. 22. 12:32

systemd Type=notify 기준 정리

Type=notify는 서비스가 실제로 준비를 마친 시점에 sd_notify()READY=1을 보내고, 그때 systemd가 후속 유닛 시작을 진행하게 만드는 방식이다. 2026년 6월 22일 기준 upstream systemd 공식 문서를 보면 장기 실행 서비스의 기본값으로는 대체로 Type=exec가 권장되지만, 서비스 코드가 자신의 준비 완료 시점을 정확히 알고 있고 그 시점을 systemd에 알려야 한다면 Type=notify가 더 맞다.

실무에서 자주 헷갈리는 지점은 두 가지다. 단순히 프로세스 실행 성공만 확인하면 되는지, 아니면 포트 바인딩이나 내부 초기화까지 끝난 뒤에 다른 유닛이 따라오게 해야 하는지다. 이 글은 Type=notify, NotifyAccess=, sd_notify()의 의미와 무난한 선택 기준만 정리한다.

Type=notify는 무엇을 바꿀까?

upstream systemd.service 문서에 따르면 Type=notify는 동작 방식이 Type=exec와 비슷하지만, 서비스가 시작 완료를 알리는 READY=1 메시지를 보낼 때까지 systemd가 follow-up unit 시작을 미룬다. 반대로 Type=exec는 서비스 바이너리의 execve() 성공까지만 확인하고 다음 작업으로 넘어간다.

이 차이는 의존 관계가 있는 서비스에서 중요하다. 예를 들어 데몬이 프로세스는 떴지만 실제로는 포트 바인딩, 캐시 로딩, 초기 동기화가 끝나야 요청을 받을 수 있다면 Type=exec만으로는 너무 이르게 시작 성공으로 판단될 수 있다.

먼저 어떤 타입을 고르면 될까?

타입 systemd가 시작 완료로 보는 시점 우선 고려할 상황
simple fork 직후 대기 없이 바로 다음 작업을 진행해도 되는 매우 단순한 서비스
exec execve() 성공 직후 장기 실행 서비스의 기본 출발점
notify 서비스가 READY=1을 보낸 뒤 서비스 코드가 준비 완료 시점을 직접 알려야 할 때
forking 부모 프로세스 종료 뒤 기존 데몬화 방식을 유지해야 하는 레거시 서비스

공식 문서는 장기 실행 서비스에 대해 Type=exec를 권장 선택지로 설명한다. 서비스 실행 파일이 없거나 User= 같은 실행 준비 단계에서 실패했을 때 이를 제대로 추적하기 쉽기 때문이다. 다만 서비스 코드 내부 초기화 완료 시점에 맞춰 정확히 순서를 제어해야 하면 notify, D-Bus 이름 획득이 준비 완료 조건이면 dbus가 더 적합하다.

Type=notify를 고를 만한 기준은 무엇일까?

첫째, 후속 유닛이나 클라이언트가 "프로세스가 떴다"가 아니라 "서비스가 실제로 준비됐다"는 신호를 필요로 할 때다. 공식 문서 기준 notify는 서비스 코드가 정확히 언제 준비 완료로 볼지 결정할 수 있게 해 준다.

둘째, 서비스가 reload 완료나 watchdog keep-alive까지 systemd와 같은 채널로 통신해야 할 때다. upstream 문서는 notify-reloadWatchdogSec= 모두 notification socket 사용을 전제로 설명한다.

반대로 서비스 코드에 sd_notify() 지원이 없고, 준비 완료 시점을 외부에서 확실히 알 수 없다면 Type=notify를 억지로 고르는 것이 맞지 않다. 이런 경우에는 Type=exec를 쓰거나, 레거시 데몬이면 forking을 유지하는 편이 더 단순하다.

NotifyAccess=는 왜 같이 봐야 할까?

Type=notify는 notification socket에 메시지를 보내는 방식이므로, 어떤 프로세스의 메시지를 systemd가 신뢰할지 정하는 NotifyAccess=를 같이 봐야 한다. 공식 문서에 따르면 값은 none, main, exec, all 중 하나다.

허용 범위 무난한 사용 상황
main 메인 프로세스만 허용 주 프로세스가 직접 READY=1을 보내는 일반적인 경우
exec Exec*=로 시작된 main/control 프로세스 허용 control process도 상태 통지를 해야 할 때
all 같은 cgroup의 모든 프로세스 허용 보조 프로세스가 통지를 보내야 하지만 구조를 바꾸기 어려울 때

중요한 점은 공식 문서가 Type=notify 또는 WatchdogSec=를 사용할 때 NotifyAccess=를 열어 두라고 설명한다는 것이다. 값을 따로 적지 않거나 none이면 systemd가 강제로 main으로 바꾼다.

또한 sd_notify 문서는 보조 프로세스가 메시지를 보낸 직후 바로 종료하면, 심지어 NotifyAccess=all이어도 systemd가 해당 메시지를 유닛에 제대로 귀속시키지 못해 무시할 수 있다고 설명한다. 따라서 메인 프로세스나 systemd가 직접 시작한 프로세스가 통지하도록 설계하는 편이 안전하다.

sd_notify()로 무엇을 보낼 수 있을까?

가장 기본적인 메시지는 READY=1이다. upstream sd_notify 문서에 따르면 이 값은 서비스 시작 완료 또는 reload 완료를 알릴 때 쓰이며, READY=0 같은 값은 정의돼 있지 않다.

STATUS=...를 함께 보내면 systemctl status 같은 곳에 사람이 읽을 수 있는 상태 문자열을 남길 수 있다. reload를 추적해야 하면 Type=notify-reload와 함께 RELOADING=1, MONOTONIC_USEC=..., 그리고 reload 완료 후 다시 READY=1을 보내는 흐름을 쓴다.

watchdog를 켠 서비스는 주기적으로 WATCHDOG=1을 보내 keep-alive를 갱신한다. 서비스가 내부 오류를 감지했고 watchdog 동작으로 처리하고 싶다면 WATCHDOG=trigger도 보낼 수 있다.

운영에서 무난한 선택 기준은 어떻게 잡을까?

상황 무난한 선택 이유
실행 파일 존재와 권한 문제만 잡으면 되는 일반 데몬 Type=exec 실행 준비 실패를 명확히 잡고 설정이 단순함
포트 바인딩, 캐시 준비, 초기 동기화 이후에만 준비 완료로 봐야 하는 데몬 Type=notify + NotifyAccess=main 서비스 코드가 정확한 readiness 시점을 통지할 수 있음
reload 완료까지 systemd가 추적해야 하는 서비스 Type=notify-reload reload 시작과 완료를 상태 메시지로 표현 가능
기존 daemonize 방식과 PID 파일 의존성이 남아 있는 서비스 Type=forking 레거시 호환 목적, 다만 신규 설계의 기본값으로 보기는 어려움

핵심은 Type=notify가 더 "좋은" 타입이라기보다, readiness를 서비스가 스스로 선언해야 할 때 필요한 타입이라는 점이다. 준비 완료의 기준을 코드 안에서 정의하지 못한다면 오히려 운영 복잡도만 늘어난다.

자주 헷갈리는 질문

Q. 장기 실행 서비스면 항상 Type=notify가 더 나을까?

그렇게 보기 어렵다. 공식 문서는 장기 실행 서비스의 일반적인 권장값으로 Type=exec를 설명한다. notify는 readiness를 코드가 정확히 선언할 필요가 있을 때 선택하는 쪽에 가깝다.

Q. NotifyAccess=all로 두면 가장 안전할까?

항상 그렇지는 않다. 허용 범위를 넓히는 대신 어떤 프로세스가 상태 통지를 보냈는지 추적이 어려워질 수 있고, 보조 프로세스가 바로 종료하면 귀속 race가 남을 수 있다. 메인 프로세스가 직접 보내는 구조라면 main이 더 단순하다.

Q. reload도 같은 방식으로 처리할 수 있을까?

가능하다. 다만 공식 문서는 reload 추적이 필요하면 일반 notify보다 notify-reload를 권장한다. 이 경우 reload 시작 시 RELOADING=1MONOTONIC_USEC=..., 완료 시 READY=1을 보내야 한다.

정리

Type=exec는 실행 준비 단계의 오류를 정확히 잡는 기본값이고, Type=notify는 서비스 코드가 readiness를 선언해야 할 때 쓰는 선택지다. 대부분의 서비스는 먼저 exec를 기준으로 생각하고, 실제 준비 완료 시점을 외부에 알려야 할 이유가 분명할 때만 notify로 올리는 편이 안전하다.

2026년 6월 22일 기준 upstream systemd 공식 문서를 기준으로 보면, Type=notify를 도입할 때 같이 확인해야 할 핵심은 세 가지다. READY=1을 언제 보낼지, 누가 보낼지에 맞는 NotifyAccess= 값이 무엇인지, 그리고 reload나 watchdog까지 같은 채널로 다룰지다.

참고 자료

반응형
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사