BlueByte
Start request repeated too quicklyFixed

systemd: Start request repeated too quickly

작성 Haneul Seo2026년 9월 27일 업데이트8 min

안녕하세요, BlueByte입니다. 스스로 재시작하던 서비스가 내려간 채로 남고, systemctl status에는 failed가, 저널에는 Start request repeated too quickly가 찍히는 경우가 있습니다. 이 줄은 systemd의 시작 속도 제한이지 진짜 실패가 아닙니다. 서비스가 연달아 여러 번 죽었고 systemd가 재시도를 멈춘 것입니다. 오늘은 이 제한이 무엇을 세는지, 그 아래 숨은 크래시를 찾는 법, 원인별 해결, 그리고 예방까지 하나씩 짚어보겠습니다.

제한에 걸렸을 때 저널과 systemctl이 보여주는 것

systemd 255(Ubuntu 24.04)에서 프로그램이 1로 종료하고 Restart=on-failure인 유닛으로 재현한 저널입니다:

myapp.service: Scheduled restart job, restart counter is at 5.
myapp.service: Start request repeated too quickly.
myapp.service: Failed with result 'exit-code'.
Failed to start myapp.service - My App.

systemctl start의 문구는 systemd가 기록한 결과(result)에 따라 달라집니다. 결과가 start-limit-hit이면 다음 문구와 함께 reset-failed를 쓰라는 안내가 나옵니다:

Job for myapp.service failed because start of the service was attempted too often.

제 255 테스트에서는 유닛이 처음 결과인 exit-code를 유지해서 systemctl start가 대신 the control process exited with error code라고 했습니다. 현재 systemd 소스는 여기서 start-limit-hit을 기록하므로, 어떤 문구가 보일지는 버전에 따라 다릅니다. 메시지 하나를 믿기보다 저널에서 repeated too quickly를 검색하세요.

systemd가 재시도를 멈추는 이유

모든 유닛에는 시작 제한이 있습니다. StartLimitIntervalSec= 안에 StartLimitBurst=번보다 많이 시작하면 이후 시작은 거부됩니다. 둘 다 [Unit] 섹션에 두며 기본값은 10초와 5회입니다. systemd.service 매뉴얼은 Restart=도 같은 제한을 받는다고 명시하고, RestartSec=의 기본값은 100ms입니다. 그래서 시작하자마자 죽는 프로그램은 1초도 안 되어 다섯 번을 소진하고, systemd는 포기합니다. 무한 루프를 막는 장치이지 버그가 아닙니다.

원인은 세 갈래입니다:

  • 프로그램 자체가 매번 실패합니다: 잘못된 설정, 없는 파일, 사용 중인 포트, 틀린 권한.
  • 필요한 것(데이터베이스, 마운트, 네트워크)이 아직 준비되지 않아 잠깐 실패하는데, 100ms 간격으로는 준비될 틈이 없습니다.
  • 외부의 무언가가 계속 재시작합니다. Restart=든, 사람이든, 배포 스크립트든 시작은 모두 셉니다.

먼저 속도 제한 아래의 크래시 찾기

외울 필요는 없습니다. 세 명령이면 원인이 갈립니다:

systemctl show myapp -p Result -p NRestarts -p RestartUSec -p StartLimitIntervalUSec -p StartLimitBurst
journalctl -u myapp -b --no-pager | grep -v 'Scheduled restart' | tail -n 30
systemctl cat myapp

제 테스트는 NRestarts=5, StartLimitIntervalUSec=10s, StartLimitBurst=5를 출력했습니다. 중요한 건 repeated too quickly 위쪽 저널 줄입니다. 프로그램 자체의 오류이거나, ExecStart= 바이너리를 아예 실행하지 못했다는 status=203/EXEC입니다. 시작 사이에 크래시가 없다면 누가 계속 재시작하는지 찾아보세요.

원인별 해결

매번 실패하는 프로그램이라면 오류를 고친 뒤 카운터를 비우고 다시 시작합니다. reset-failed는 카운터만 비울 뿐 그것만으로는 아무것도 바꾸지 않습니다:

sudo systemctl reset-failed myapp
sudo systemctl start myapp
systemctl is-active myapp
# active

아직 준비되지 않은 의존성이 원인이라면 벤더 유닛을 고치지 말고 drop-in으로 재시작 간격을 벌립니다:

sudo systemctl edit myapp
[Service]
Restart=on-failure
RestartSec=5s

어림 규칙은 이렇습니다. RestartSec × StartLimitBurst가 StartLimitIntervalSec보다 길면 재시작만으로는 제한에 걸릴 수 없습니다. 테스트 유닛에 RestartSec=3s를 주었더니 14초 뒤에도 NRestarts=4, SubState=auto-restart로 — failed가 아니라 계속 재시도 중이었습니다. systemd 254 이상에서는 RestartSteps=와 RestartMaxDelaySec=로 고정 지연 대신 점점 늘어나는 back-off를 줄 수 있습니다.

외부 재시작이 원인이라면 스크립트나 타이머를 고치세요. StartLimitBurst=를 올리면 가려질 뿐입니다.

따라 해 보기: PostgreSQL보다 먼저 뜨는 API

API 유닛이 부팅 때 시작해 PostgreSQL에 닿지 못하고 connection refused를 남기고 종료합니다. 100ms 간격 재시작 다섯 번이 데이터베이스가 연결을 받기 전에 끝나 버리고, API는 누군가 로그인할 때까지 failed로 남습니다. 해결은 두 부분입니다. 데이터베이스 뒤로 순서를 잡고, 재시도할 여유를 줍니다:

[Unit]
After=postgresql.service
Wants=postgresql.service
 
[Service]
Restart=on-failure
RestartSec=5s

다음 재부팅 후 systemctl show api -p NRestarts -p ActiveState는 재시작 한두 번과 ActiveState=active를 보여줍니다. 데이터베이스가 연결을 받기까지 시간이 걸리면 순서만으로는 부족하기 때문에 지연도 남겨 둡니다.

끝까지 확인하고 재발 막기

systemctl is-active myapp를 실행한 다음, 일부러 systemctl restart myapp를 한 번 하면서 journalctl -u myapp -f를 지켜보세요. 재발을 막으려면 Restart=가 있는 유닛에는 RestartSec=를 명시하고, 실제 의존성은 After=/Wants=로 선언하고, failed 상태 유닛(systemctl --failed)에 알림을 거세요. StartLimitIntervalSec=0은 제한을 완전히 끕니다. 그러면 고장 난 프로그램이 RestartSec 간격으로 영원히 재시도하니, 적당한 지연과 함께만 쓰세요.

203/EXEC, 시작 타임아웃과 다른 점

status=203/EXEC는 systemd가 ExecStart= 프로그램을 실행하지 못했다는 뜻입니다 — 틀린 경로, 실행 비트 누락. 이 오류 아래 숨은 크래시인 경우가 많습니다. Job for myapp.service failed because a timeout was exceeded는 한 번의 시작이 TimeoutStartSec=보다 오래 걸렸다는 뜻입니다. 빠른 시작 여러 번이 아니라 느린 시작 한 번입니다.

다음에 서비스가 내려간 채로 남으면 이 순서를 거꾸로 따라가 보세요. repeated too quickly 위쪽 저널을 읽고, 그 오류를 고친 다음, 재시작 간격을 바꿔야 할지 판단하세요.

관련 질문

systemctl reset-failed로 해결되나요?

아닙니다. 시작 카운터를 비우고 failed 상태를 지워서 유닛을 다시 수동으로 시작할 수 있게 할 뿐입니다. 프로그램이 여전히 시작하자마자 죽는다면 몇 초 안에 다시 제한에 걸립니다. 저널에서 찾은 오류를 먼저 고친 뒤 reset하고 시작하세요.

그냥 StartLimitIntervalSec=0으로 두면 안 되나요?

그러면 속도 제한이 꺼져서 systemd가 고장 난 프로그램을 RestartSec 간격으로 영원히 재시작합니다. 5초 같은 적당한 지연이라면 스스로 복구돼야 하는 서비스에 괜찮을 수 있지만, 기본 100ms라면 저널을 채우는 촘촘한 루프가 됩니다. 더 긴 RestartSec를 우선하고, systemd 254 이상이라면 RestartSteps=와 RestartMaxDelaySec=도 고려해 보세요.

제가 직접 친 systemctl restart도 제한에 포함되나요?

네. 제한은 무엇이 계기였든 유닛의 시작 횟수를 셉니다. 서비스를 반복해서 재시작하는 배포 스크립트나, 짧은 간격으로 연달아 친 재시작 몇 번이 프로그램이 한 번도 죽지 않았는데도 제한을 걸 수 있습니다.

StartLimitBurst를 설정했는데 systemctl show는 여전히 5를 보여줍니다.

설정이 어디로 갔는지 확인하세요. StartLimitIntervalSec=와 StartLimitBurst=는 [Unit] 섹션에 문서화돼 있으니 drop-in에서도 [Unit] 아래에 두세요. 그런 다음 systemctl cat myapp과 systemctl show myapp -p StartLimitBurst로 합쳐진 결과를 확인합니다. systemctl edit 대신 파일을 직접 고쳤다면 systemctl daemon-reload로 다시 읽게 하세요.

제한에 걸렸을 때 systemd가 더 큰 조치를 하게 할 수 있나요?

네. [Unit] 섹션의 StartLimitAction=은 reboot, poweroff 같은 다른 실패 조치와 같은 값을 받고 기본값은 none입니다. 그 유닛 없이는 머신이 쓸모없는 경우를 위한 것이라, 일반 서비스라면 systemctl --failed에 알림을 거는 편이 대개 낫습니다.

참고 자료

Haneul Seo

Infrastructure engineer · 10+ years running Linux fleets

같은 카테고리 다른 글

Too many authentication failuresFixed

SSH: Received disconnect ... Too many authentication failures

agent가 서버가 허용하는 것보다 많은 키를 내밀고 있습니다. sshd가 들여다보는 공개키 하나하나가 MaxAuthTries 시도를 한 번씩 소모하고 — 기본 6회, 하드닝된 호스트에서는 3회인 경우가 많습니다 — 정작 맞는 키는 차례가 오기 전에 연결이 끊깁니다. IdentitiesOnly=yes와 명시적 IdentityFile로 키 하나를 고정하면 시도 횟수가 1로 떨어집니다.

OpenSSH
1722Fixed

Active Directory: 복제가 error 1722(The RPC server is unavailable)로 실패

RPC는 하위 계층이 연결에 실패했을 때 1722(0x6ba, RPC_S_SERVER_UNAVAILABLE)를 보고합니다. 따라서 진짜 원인은 RPC 자신이 아니라 DNS, 차단된 포트, 두 도메인 컨트롤러 중 한쪽의 호스트 설정입니다. repadmin이 어느 파트너가 실패하는지 알려주고, dcdiag /test:dns가 이름 해석을 배제하며, Test-NetConnection과 동적 포트 범위가 방화벽 문제를 가릅니다. 가장 흔한 실수는 TCP 135만 허용하고 49152–65535는 막아 둔 규칙입니다.

Windows Server Active Directory
Windows Server RDSFixed

Windows Server RDS: The remote session was disconnected because there are no Remote Desktop License Servers available to provide a license

120일 RD Licensing 유예 기간이 끝났는데 세션 호스트가 쓸 수 있는 라이선스 서버가 없어 세션을 거부하는 상황입니다. GetGracePeriodDays 의 DaysLeft 가 0 이고 SpecifiedLSList 가 비어 있으면 몇 초 만에 확인됩니다. 해결은 활성화된 라이선스 서버와, 호스트 버전을 감당할 만큼 새 CAL 입니다. 2019 CAL 은 2022 세션 호스트를 서비스하지 못합니다. 여기에 배포 또는 Licensing 정책 설정과 두 서버 사이의 RPC 포트 개방이 따라옵니다.

Windows Server RDS
0x80070035 / Event ID 31017Workaround

Windows 11: NAS 공유 폴더를 열 때 "조직의 보안 정책이 인증되지 않은 게스트 액세스를 차단" (0x80070035)

Windows 10 Enterprise/Education/Pro for Workstations, Windows 11 Pro, Windows Server 2019 이후의 SMB 클라이언트는 기본적으로 게스트 로그온을 거부하고, Windows 11 24H2 Enterprise/Pro/Education 은 게스트 세션이 할 수 없는 SMB 서명까지 요구합니다. 그래서 게스트 접근만 제공하는 NAS 공유는 'block unauthenticated guest access' 대화상자, Error code 0x80070035, 또는 System error 3227320323 으로 실패하고, SmbClient/Security 로그에 Event ID 31017 'Rejected an insecure guest logon' 이 남습니다. Microsoft 가 권하는 해결은 NAS 에 실제 계정을 만들고 펌웨어에서 서명을 지원하게 하는 것입니다. Set-SmbClientConfiguration -EnableInsecureGuestLogons $true(24H2 는 -RequireSecuritySignature $false 까지)는 비상구이며, 그 클라이언트의 서명과 암호화를 포기하는 대가가 있습니다.

Windows (SMB client)
E: Could not get lock /var/lib/dpkg/lock-frontendFixed

Ubuntu/Debian: E: Could not get lock /var/lib/dpkg/lock-frontend — 누가 쥐고 있고 어떻게 기다리는지

다른 패키지 관리자, 대개 부팅 때 persistent systemd 타이머로 발화한 Ubuntu 의 unattended-upgrades 가 여러분의 apt-get 이 도는 동안 dpkg 프런트엔드 락을 쥐고 있는 것입니다. Ubuntu 는 apt 바이너리에만 binary::apt::DPkg::Lock::Timeout "120" 을 실어 두어서 apt-get 은 즉시 포기하고 apt 는 기다립니다. 메시지의 PID 를 읽고, 실행이 끝나게 두거나 apt-get 에 -o DPkg::Lock::Timeout=<초> 를 주고, dpkg --configure -a 는 실제로 중단된 실행 뒤에만 쓰고, 락 파일은 절대 지우지 마세요. 보유자가 종료하면 커널이 푸는 fcntl 락입니다.

APT (Ubuntu/Debian)
xcrun: error: invalid active developer pathFixed

macOS: xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools)

macOS의 /usr/bin에 있는 git·make·clang 같은 개발 명령은 활성 developer 디렉터리로 넘겨주는 shim이고, xcrun은 xcode-select가 가리키는 디렉터리에 도구가 없다고 보고하는 것입니다 — 대개 macOS 메이저 업그레이드가 /Library/Developer/CommandLineTools를 비워 두었거나, Xcode가 옮겨지거나 삭제된 경우입니다. xcode-select -p와 패키지 영수증을 확인한 뒤 xcode-select --install로 Command Line Tools를 다시 설치하거나, 실제로 있는 Xcode를 xcode-select로 가리키면 됩니다.

macOS