![ExecStop 구문 없이 서비스 데몬을 어떻게 정상적으로 종료할 수 있습니까?](https://linux55.com/image/217501/ExecStop%20%EA%B5%AC%EB%AC%B8%20%EC%97%86%EC%9D%B4%20%EC%84%9C%EB%B9%84%EC%8A%A4%20%EB%8D%B0%EB%AA%AC%EC%9D%84%20%EC%96%B4%EB%96%BB%EA%B2%8C%20%EC%A0%95%EC%83%81%EC%A0%81%EC%9C%BC%EB%A1%9C%20%EC%A2%85%EB%A3%8C%ED%95%A0%20%EC%88%98%20%EC%9E%88%EC%8A%B5%EB%8B%88%EA%B9%8C%3F.png)
저는 시스템 초보자입니다.
ExecStop=
systemd 서비스 단위 파일의 구문 없이 서비스를 정상적으로 종료하는 방법을 알고 싶습니다.
예를 들어 의 경우 mongod.service
아니요 입니다 ExecStop=
.
[Unit]
Description=MongoDB Database Server
Documentation=https://docs.mongodb.org/manual
After=network.target
[Service]
User=mongodb
Group=mongodb
ExecStart=/usr/bin/mongod --config /etc/mongod.conf
PIDFile=/var/run/mongodb/mongod.pid
# [The rest, irrelevant setrlimit(2)/sh(1) `ulimit' settings, such as...]
LimitFSIZE=... [...are all snipped.]
[Install]
WantedBy=multi-user.target
ExecStop=
그런데 제 경우에는 파일을 삭제 serviceDaemon.service
하고 를 입력하면 systemctl stop command
제대로 닫히지 않습니다.
× serviceDaemon.service - server integrity checker
Loaded: loaded (/etc/systemd/system/serviceDaemon.service; disabled; vendor preset: enabled)
Active: failed (Result: timeout) since Tue 2023-02-28 19:57:30 KST; 3min 38s ago
Process: 1235476 ExecStart=/opt/esm/bin/serviceDaemon -D 9 -d (code=killed, signal=KILL)
Main PID: 1235476 (code=killed, signal=KILL)
CPU: 395ms
Feb 20 14:36:41 esm-dev systemd[1]: Started server integrity checker.
Feb 28 19:56:00 esm-dev systemd[1]: Stopping server integrity checker...
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: State 'stop-sigterm' timed out. Killing.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: Killing process 1235476 (intchecker) with signal SIGKILL.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: Killing process 1235478 (intchecker) with signal SIGKILL.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: Killing process 1235479 (intchecker) with signal SIGKILL.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: Main process exited, code=killed, status=9/KILL
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: Failed with result 'timeout'.
serviceDaemon
Mongodb와 같은 명령이 서비스를 제대로 종료하지 않는 이유를 알고 싶습니다 systemctl stop
.
답변1
시스템이 어떻게 작동하는지 이해하는 가장 좋은 방법은 가능한 모든 방법으로 시스템을 깨뜨리는 것입니다..
―익명인지, 어린 시절인지는 잘 기억나지 않는다.
따라서 귀하의 실험은 매우 훌륭하고 중요한 교육적 가치를 갖고 있습니다. 많은 사람들은 systemd를 마법과도 같은 기술로 봅니다. 그것은 틀렸습니다. 일관성이 없지만 잘 문서화되어 있는 시스템 서비스 관리자입니다. 이는 까다로우며 설명서를 읽어야 합니다. 그들은 매우 완벽합니다.
귀하의 질문에 대한 대답은 이것이 systemd에서 일반적이며 상황에 따라 다르다는 것입니다. systemd는 복잡하고 유연한 시스템 서비스 관리자입니다. 그것은 주로 의존한다유형의 서비스는 Type=
및 의 부재/존재로 정의됩니다 BusName=
. 귀하의 경우와 같이 두 가지가 모두 없으면 서비스는 다음과 같습니다.단순한: systemd는 시작 후 10밀리초 후에 종료되더라도 시작이 성공했다고 가정하고 이를 실행합니다. 그 일이 일어날지 전혀 알 수 없었고,기본설계 목표는 최신 56코어 CPU에서 시스템을 가능한 한 빨리 작동 순서대로 만드는 것입니다. 누가 10밀리초를 낭비하겠는가...
systemd는 서비스가 실제로 성공적으로 시작되었는지 가능한 한 정확하게 알고 싶어하기 때문에 서비스 시작을 위한 다양한 프로토콜이 있습니다. 이는 Type=
systemd.service(5) 매뉴얼의 설정에 설명되어 있습니다. 그 중에서 오직일회용의다양한 유형: 서비스는 systemd에 의해 "활성"으로 간주되지만 빠르게 실행되고 종료 코드 0으로 종료됩니다. 당신이하고 싶다면 이것은 의미가 있습니다무엇장치가 시작될 때와 언제다른 것멈췄지만 중간은 아닙니다. 성공하면 활성화되며 상태를 확인할 때 녹색 버튼이 표시됩니다. 당신이 그것을 멈추면, 그것은 그 ExecStop=
일을 합니다. 예를 들어, Linux NFS4 서버는 서비스 시스템 장치가 시작 시에만 활성화되고 중지 시 비활성화되는 커널 기능으로, 커널을 호출하고 종료하는 데 몇 나노초가 걸립니다. NFS 서버가 서비스를 제공하는 동안 프로세스를 실행할 필요는 없습니다. 해당 유닛이 활성 상태이지만 실행 중인 사용자 공간 프로세스가 없습니다.
다른 모든 유형의 경우 없음 ExecStop=
, 동작시작하다서비스 종료도 동일합니다. 서비스에 신호를 보냅니다. 이 신호는 ,(또는 재시작의 경우) 또는 설정되지 않은 경우 표준 서비스 종료 신호 SIGTERM(systemd.kill(5) 참조) KillSignal=
에 의해 정의됩니다 . RestartKillSignal=
이것은 맹금류가 지구를 배회한 이후로 모든 "전통적인" Unix 데몬이 종료되도록 지시받은 방식입니다. 서비스를 중지할 수 없는 경우에도 프로토콜이 다릅니다. 예를 들어 dbus를 통해 systemd와 통신하는 서비스는 종료하는 데 더 많은 시간을 요청할 수 있습니다. 이를 사용할 수 없는 경우 이 설정을 사용하거나 TimeoutStopSec=
(설명서의 system.conf(5)) system.conf
에 설정된 기본값 DefaultTimeoutStopSec=
또는 시스템 공급업체가 변경하지 않는 한 일반적으로 90초인 컴파일 시간 기본값을 사용합니다. 그 후 systemd는 마스킹하거나 무시할 수 없는 SIGKILL을 사용하여 프로세스를 무례하게 종료합니다. 프로세스가 종료되고 해제할 수 있는 메모리가 해제되며 종료된 것으로 간주되어 좀비가 됩니다. 그러면 모든 커널 모듈이 관심을 잃습니다. 디스크 또는 GPU DMA 전송 중에 종료됩니다. read(3) 내에서 커널은 드라이버 모듈에 가능한 한 빨리 전송을 중단하거나 완료하도록 알리고 모든 시스템 테이블에서 제거됩니다. 즉, 다른 프로세스와 마찬가지로 종료됩니다. (a) 하위 프로세스 및 (b) 제어 그룹과 관련된 몇 가지 미묘한 부분이 있지만 매뉴얼을 읽고 자세한 내용을 알아볼 수 있습니다.
자신이 만든 문제로 돌아가서:
Type=
및 가 없으면BusName=
서비스는 다음과 같습니다.단순한.- 결석
ExecStop=
, 하나단순한SIGTERM 신호를 서비스에 보내고 (아마도) 서비스가 종료될 때까지 90초를 기다립니다.그리고 그 자식 프로세스. - 실패하면 systemd는 완전한 사무라이 공격을 수행하고 SIGKILL을 사용하여 무자비하게 죽입니다.
당신의 모범은 참으로 훌륭합니다! 한 줄씩 분석해 보겠습니다.
Feb 28 19:56:00 esm-dev systemd[1]: 서버 무결성 검사기를 중지하는 중...
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: status " stop-sigterm" 시간이 초과되었습니다. 죽이는.
두 메시지 사이에 경과된 시간은 정확히 90초입니다. 이 서비스는 SIGTERM을 수신할 때 중지되도록 설계되지 않은 것 같습니다. 두 번째 줄은 내부 시스템 상태가 SIGTERM을 전송하고 대기 중이며 시간 초과되었음을 나타냅니다. "Kill"은 SIGKILL 신호를 보내는 것을 의미하며, 프로세스는 이를 인지하지도 못합니다. 이는 제거하라는 커널에 대한 신호입니다.그 일최대한 빨리.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: SIGKILL 신호를 사용하여 프로세스 1235476(intchecker)을 종료합니다.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: 신호 SIGKILL을 사용하여 프로세스 1235478(intchecker)을 종료합니다.
Feb 28 19:57:30 esm-dev systemd[1]: serviceDaemon.service: 신호 SIGKILL을 사용하여 프로세스 1235479(intchecker)를 종료합니다.
systemd는 전체 프로세스의 생성을 처리할 만큼 똑똑합니다. 모든 하위 프로세스도 동시에 무조건 종료됩니다(만기본PID는 systemd와 대화하며 하위 프로세스는 부적절하게 동작하지 않는 한 systemd의 비즈니스가 아닙니다.
2월 28일 19:57:30 esm-dev systemd[1]: serviceDaemon.service: 기본 프로세스가 종료되었습니다. 코드=killed, 상태=9/KILL
그룹 리더 아래에서 시작된 프로세스와 모든 것이 SIGKILL에 의해 종료되면(9는 SIGKILL의 값이며 kill -SIGKILL <pid>
정확히 동일한 명령 kill -KILL <pid>
입니다 kill -9 <pid>
), 좀비화 여부에 관계없이(이것은 시스템 문제가 아니라 커널 문제입니다), systemd 내부적으로 서비스가 실패하도록 설정합니다.
2월 28일 19:57:30 esm-dev systemd[1]: serviceDaemon.service: '시간 초과' 결과로 인해 실패했습니다.
이제 종속성 그래프를 계속 처리할 수 있습니다.
학살이 시작되면 모든 이벤트의 타임스탬프는 19:57:30입니다. 지금 systemd의 문제는 배신자 프로세스를 최대한 빨리 제거하는 것입니다. 이 기능이 너무 뛰어나서 서비스를 시작할 때 최대한 빨리 SIGTERM에 대한 핸들러를 구축해야 합니다. 더 효과적으로 협업하세요.
서비스 작성자에게는 몇 가지 옵션이 있습니다. ㅏ단순한서비스는 가장 빠르지만 정보가 가장 적습니다. systemd는 일단 포크되면 시작된 내부 작업 단위를 게시합니다.일하다,바이너리를 시작합니다.ExecStart=
파일이 누락 되더라도 서비스는 성공적으로 시작됩니다.빨간색 버튼과 전반적인 "저하" 상태가 표시되지만 다른 서비스가 시작되는 것을 막지는 않습니다.
더 확실하지만 더 느린 다음은구현하다유형: systemd는 게시가 성공하기 전에 프로세스가 시작되는지 확인합니다.
이 시점부터 dbus를 통해 systemd와 통신할지 여부를 결정하십시오. 시스템이 systemd에 의해 관리된다는 것을 알고 있는 경우 이는 유용합니다. 일반적으로 높은 수준의 API가 있는 링크에 연결 libsystemd.so.1
하지만 그것 없이도 작업할 수 있습니다. 이는 잘 알려진 이름을 가진 UNIX 소켓일 뿐입니다. 이 라이브러리에 의존하고 싶지 않지만 존재하는 경우 dbus 자체와 통신하는 일부 코드를 본 적이 있습니다. 이러한 상황은 매우 드물지만 재컴파일 없이 systemd 또는 기존 init에 의해 동일한 바이너리를 시작할 수 있습니다.
dbus를 사용하면 다음 단계의 확실성은 다음과 같습니다.버스유형. systemd는 dbus에 대한 연결이 설정되면 서비스가 시작되는 것으로 간주합니다(그러므로 주저하지 말고 가능한 한 빨리 시작하십시오. 이는 전체 시스템의 시작에 영향을 미칩니다).
다음은통지하다제공하다. Systemd는 서비스가 dbus 연결에 게시된 후에만 READY=1
성공적으로 게시됩니다 . 이는 systemd에 가장 유용한 정보입니다.긍정적인 확인서비스가 시작됩니다.
두 유형 모두 fork(2)가 필요하지 않습니다.
그렇지 않으면 서비스를 "전통적인" 자체 데몬으로 구현할 수 있습니다. 시작 후 모든 초기화를 수행하고 모든 것이 준비되면 프로세스를 두 개의 클론으로 분기(2)합니다. 원본이 종료되고 성공 상태가 systemd에 반환됩니다. 두 번째는 여전히 실행 중이며 주요 장기 실행 데몬입니다. 전통적으로 파일 시스템 <servicename>.pid
아래에 파일을 작성 /run
하지만 systemd는 일반적으로 해당 파일 없이 분기된 프로세스를 찾습니다. 하나를 저장하면 설정을 통해 시스템에 위치를 알려줍니다 PIDFile=
. 그대로 두면 systemd가 이를 제거합니다. 이 파일은 "레거시" init/rc 시스템에만 필요합니다. Type=
이러한 유형의 서비스 기능은 다음과 같습니다.분기. 그것은 또한 제공합니다앞으로 시작 표시체계적으로통지하다유형. 다른 장기 실행 유형은 이를 수행할 수 없습니다(일회용의그러나 시작 명령도 가능한 한 빨리 완료되어야 합니다.
이 주문은 systemd에 관한 것입니다.확증하다서비스가 시작되었습니다. 기동속도로 판단하면 비율이 거의 반대이고,단순한유형은 가장 잘 수행되는 유형입니다. 따라서 초기화를 완료하기 위해 다른 서비스가 귀하의 서비스에 의존하지 않는다는 것을 알고 있는 경우 Fast를 선택하십시오. 그렇지 않으면 가장 유익한 것을 선택하십시오.분기또는통지하다, 이는 시스템 시작 시간에 가장 큰 영향을 미친다는 점을 명심하세요.