Periodicamente reinicie o serviço systemd

3

Eu tenho um pequeno programa C que eu estou executando já rodando como um daemon com o systemd. Atualmente, restart está definido como always . Gostaria de ajustar a unidade para que ela seja reiniciada periodicamente, digamos, todos os dias, caso meu código tenha alguns vazamentos de memória.

Sei que o systemd oferece várias opções de reinicialização, como WatchdogSec ou RuntimeMaxSec , mas elas parecem resultar em um sinal SIGABRT , que, acredito, não consigo entender no meu código, por isso não posso desligue graciosamente.

Existe alguma maneira de uma unidade systemd desligar e reiniciar periodicamente seu serviço? Ou é possível ouvir o sinal SIGABRT no meu código e lidar com isso graciosamente?

    
por Dom 23.07.2017 / 17:52

1 resposta

2

Não, você não precisa modificar nada em seu código. tão simples como, Você pode usar crontab para reiniciar seu serviço periodicamente.

  1. verifique se seu processo ainda está ativo.
  2. se estiver morto, reinicie-o.
  3. se demorou muito memória, matá-lo e reiniciá-lo.

    PID_YOURS = 'ps -a | grep "YOUR_PROCESS" | awk -F" " '{print $1}''
    MEM_USES = 'ps -eo pid,rss | grep "$PID_YOURS" | awk -F" " '{print $2}''
    

No entanto, a melhor maneira é melhorar o seu código para reduzir vazamentos de memória. Espero que você possa resolvê-lo da maneira mais simples possível.

P.S. você não pode receber exceções críticas internamente. Especialmente, erros devido a vazamentos de memória não podem ser tratados internamente como eles normalmente envolvem corrupções de heap. Portanto, é inevitável que a situação seja encerrada pelo kernel. Além disso, há uma maneira de abordá-lo de uma maneira diferente;

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.
}

OU , você pode registrar um manipulador SYSABRT para capturá-lo. mas você não pode recuperar o fluxo para trabalhar bem. você só deve executar operações de emergência para proteger seus dados no manipulador SYSABRT . (mas SYSABRT handler não tem garantia de que será executado nessa situação)

_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.
    }
}

não gaste muito tempo no manipulador SYSABRT . não, o kernel mata imediatamente. Além disso, fazer operações de alocação de memória no manipulador SYSABRT pode causar exceções críticas. então você precisa construir memória de emergência para alocar memória (temporariamente).

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;
    }
    ...
}

Finalmente , em primeiro lugar, você pode substituir a reinicialização do seu serviço pela sua própria implementação. Você pode enviar apenas uma mensagem para o seu programa através de um socket ou arquivos Unix, ou outros métodos ... Não é um problema complicado.

Soluções reais para o seu daemon.

Melhore seu daemon para interação com o Systemd.   O Systemd suporta os mecanismos Start, Restart, Stop e você os especifica conforme suas necessidades.

ou seja:

ExecStart=/your/daemon/path/and/binary start
ExecStop=/your/daemon/path/and/binary stop
Restart=always
WatchdogSec=10000
MemoryMax=2048M

ainda mais, ele suporta pré-ações e pós-ações e você pode especificá-las também. você pode lidar com métodos programáticos. Se o mecanismo de reinicialização não foi especificado, ele executa o ExecStop antes de executar o ExecStart.

Além disso, na versão recente do systemd, ele suporta o limite de memória.    MemoryLimit foi reprovado, mas MemoryMax ainda está disponível. você pode configurar um limite com opções de reinicialização. você pode ler este documento em freedesktop.org.

Se você implementar os dois lados do systemd e as interações do seu daemon, você pode lidar com isso perfeitamente.   você pode deixar seu pid para arquivar e pegar quando precisar manipular stop . ainda mais, você pode reutilizá-lo para verificar se seu daemon já está em execução. Se o seu sistema estiver desligado no estado inesperado, você deve verificar se o seu pid está correto ou existente.

Além disso, se você implementar esse método, poderá recarregar as configurações do daemon com ele. basta abrir um soquete unix como o mysqld, colocar ações como dados. Ele permite que o daemon possa parar a si mesmo ou recarregar-se com uma operação para armazenar dados importantes que devem ser armazenados.

O método

crontab ou system () pode levar seu sistema adiante à falta de recursos. Mesmo SYSABRT sinal talvez não seja executado corretamente (porque representa como situação crítica). e pesquisar seu daemon o levará para a mesma situação com o método crontab ou system ().

todos os métodos para eliminá-lo podem fazer com que seus dados não sejam salvos. você deve manipulá-lo com argumentos de linha de comando e interagir com o ciclo de gerenciamento de systemd . systemctl kill e kill para matar seu daemon, eles causam isso também. então eu não os recomendo.

finalmente, você precisa implementar rotinas de interação com argumentos de linha de comando e incluir SYSABRT handler para lidar com isso normalmente.

Ainda mais , você pode monitorar seu daemon com um fluxo em seus códigos e abrir algum canal IPC, como memória compartilhada ou Unix Socket.

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);
}

Se você quiser controlar apenas com systemd , você pode ler este documento .

Consulte a parte "Arquivos de unidade avançada" nesse documento, e você pode ler este documento também. O caso é semelhante ao seu cenário, como se um daemon não respondesse mais e não estivesse morto.

    
por 23.07.2017 / 18:51