systemd에서 데몬으로 실행되는 작은 C 프로그램이 있습니다. 현재는 restart
으로 설정되어 있습니다 always
. 코드에 메모리 누수가 발생할 경우를 대비하여 매일처럼 주기적으로 다시 시작되도록 장치를 조정하고 싶습니다.
WatchdogSec
systemd가 또는 같은 다양한 다시 시작 옵션을 제공한다는 것을 알고 있지만 이러한 옵션은 코드에서 포착할 수 없어 정상적으로 종료되지 않는다는 신호를 RuntimeMaxSec
생성하는 것 같습니다 .SIGABRT
시스템 장치가 주기적으로 서비스를 종료했다가 다시 시작할 수 있습니까? 아니면 SIGABRT
내 코드의 신호를 듣고 적절하게 처리하는 것이 가능합니까 ?
답변1
아니요, 코드에서 아무것도 수정할 필요가 없습니다. 간단한 것처럼 crontab
주기적으로 서비스를 다시 시작하는 데 사용할 수 있습니다 .
- 프로세스가 아직 살아 있는지 확인하십시오.
- 죽으면 다시 시작하세요.
메모리를 너무 많이 차지하면 종료하고 다시 시작하세요.
PID_YOURS = `ps -a | grep "YOUR_PROCESS" | awk -F" " '{print $1}'` MEM_USES = `ps -eo pid,rss | grep "$PID_YOURS" | awk -F" " '{print $2}'`
그러나 가장 좋은 접근 방식은 코드를 개선하여 메모리 누수를 줄이는 것입니다. 최대한 쉽게 해결하시길 바랍니다.
폴리스티렌내부적으로는 중요한 예외를 포착할 수 없습니다. 특히, 메모리 누수로 인한 오류는 일반적으로 힙 손상과 관련되므로 내부적으로 처리할 수 없습니다. 따라서 커널에 의한 강제 종료는 불가피합니다. 또한 접근하는 방법도 다릅니다.
while ( condition for keeping a service running ) {
system("your_program");
// blocked in above code. if the flow reached this point,
// it means that your program is dead.
}
또는, SYSABRT
핸들러를 등록하여 이를 잡을 수 있습니다. 그러나 정상적인 작업 트래픽은 복원할 수 없습니다. 핸들러의 데이터를 보호하기 위해 긴급 작업만 수행해야 합니다 SYSABRT
. (단, SYSABRT
이 경우 핸들러의 실행이 보장되지는 않습니다)
_set_abort_behavior(0, _WRITE_ABORT_MSG); // suppress warnings.
signal(SIGABRT, abrtHandler); // register handler
...
void abrtHandler(int signo) {
if(signo == SIGABORT) {
// do something for storing your datas.
signal(SIGABRT, SIG_DFL); // restore an original handler.
}
}
SYSABRT
핸들러에 너무 많은 시간을 소비 하지 마십시오 . 아니요, 커널은 즉시 이를 종료합니다. 또한 처리기 내에서 메모리 할당 작업을 수행하면 SYSABRT
심각한 예외가 발생할 수 있습니다. 따라서 (일시적으로) 메모리를 할당하려면 비상 메모리를 구축해야 합니다.
static uint8_t g_emergency[64 * 1024];
static uint8_t g_situation = 0;
static uint8_t* g_allocs = g_emergency;
void* emergency_alloc(size_t sz) {
...
if(g_situation) {
g_allocs += sz;
return g_allocs - sz;
}
...
}
마침내, 먼저 서비스 다시 시작을 자체 구현으로 대체할 수 있습니다. Unix 소켓이나 파일 또는 다른 방법을 통해 프로그램에 메시지를 보낼 수 있습니다. 이는 복잡한 질문이 아닙니다.
귀하의 데몬을 위한 진정한 솔루션입니다.
Systemd와 상호 작용하도록 데몬을 개선하십시오. Systemd는 시작, 다시 시작 및 중지 메커니즘을 지원하며 필요에 따라 이를 지정할 수 있습니다.
즉:
ExecStart=/your/daemon/path/and/binary start
ExecStop=/your/daemon/path/and/binary stop
Restart=always
WatchdogSec=10000
MemoryMax=2048M
또한 사전 및 사후 작업을 지원하며 이를 지정할 수도 있습니다. 프로그래밍 방식을 사용하여 이를 처리할 수 있습니다. 재시작 메커니즘이 지정되지 않은 경우 ExecStart가 실행되기 전에 ExecStop이 실행됩니다.
또한 최신 버전의 systemd에서는 메모리 제한을 지원합니다.
MemoryLimit
더 이상 사용되지 않지만 MemoryMax
여전히 사용 가능합니다. 다시 시작 옵션을 통해 제한을 설정할 수 있습니다. 당신은 읽을 수있다이 파일freedesktop.org에서.
systemd 상호작용과 데몬 상호작용을 모두 구현하면 완벽하게 처리할 수 있습니다. pid를 파일에 저장하고 처리해야 할 때 가져올 수 있습니다 stop
. 또한 이를 재사용하여 데몬이 이미 실행 중인지 확인할 수도 있습니다. 시스템이 예기치 않은 상태로 종료되는 경우 해당 pid가 올바른지 또는 존재하는지 확인해야 합니다.
또한 이 메서드를 구현하면 이를 사용하여 데몬 구성을 다시 로드할 수 있습니다. mysqld와 같은 유닉스 소켓을 열고 작업을 데이터로 전달하면 됩니다. 이를 통해 저장해야 하는 중요한 데이터를 저장하는 작업을 통해 데몬이 자체를 중지하거나 다시 로드할 수 있습니다.
crontab 또는 system() 메서드로 인해 시스템 리소스가 부족해질 수 있습니다. SYSABRT
신호가 올바르게 실행되지 않을 수도 있습니다(긴급 상황을 나타내기 때문입니다) . 데몬을 폴링하면 crontab 또는 system() 메서드와 동일한 상황이 발생합니다.
강제로 종료하는 모든 방법은 데이터가 저장되지 않은 상태로 남게 됩니다. systemd
이를 처리하려면 명령줄 매개변수와 대화형 관리 주기를 사용해야 합니다 . systemctl kill
그리고 kill
당신의 데몬을 죽이기 위해 그들은 또한 이런 일을 일으킬 것입니다. 그래서 나는 그들을 추천하지 않습니다.
마지막으로 명령줄 인수를 사용하여 대화형 루틴을 구현하고 SYSABRT
이를 정상적으로 처리하기 위한 핸들러를 포함해야 합니다.
또한, 코드에서 스트림을 분기하고 공유 메모리 또는 Unix 소켓과 같은 일부 IPC 채널을 열어 데몬을 모니터링할 수 있습니다.
pid_t pid = fork();
if(pid == 0) {
// children.
} else {
pid = fork();
if(pid == 0) {
// parent. you can monitor a child with IPC channel and,
// you can check your child process is alive yet.
// if your child doesn't response with IPC, you can kill it in here.
} else exit(0);
}
제어를 위해 systemd를 사용하려는 경우, 당신은 읽을 수있다이 파일.
읽을 수 있는 해당 문서의 "고급 단위 파일" 섹션을 참조하십시오.이 파일또한. 데몬이 응답을 멈춘 경우에는 아직 죽지 않은 것처럼 귀하의 경우와 유사합니다.