定期的にシステムサービスを再起動してください。

定期的にシステムサービスを再起動してください。

systemdでデーモンとして実行される小さなCプログラムがあります。現在はrestartに設定されていますalways。コードにメモリリークが発生した場合に備えて、毎日のように定期的に再起動するようにデバイスを調整したいと思います。

WatchdogSecsystemdが、または他のさまざまな再起動オプションを提供していることを知っていますが、これらのオプションはコードでキャプチャできず、正常に終了しないという信号をRuntimeMaxSec生成するようです。SIGABRT

システムデバイスが定期的にサービスをシャットダウンして再起動できますか?それともSIGABRT私のコードの信号を聞いて適切に処理することは可能ですか?

ベストアンサー1

いいえ、コードで何も修正する必要はありません。簡単なように、定期的crontabにサービスを再起動するために使用できます。

  1. プロセスがまだ生きていることを確認してください。
  2. 死んだら再起動してください。
  3. メモリが多すぎる場合は、終了して再起動してください。

    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のようなUnixソケットを開き、ジョブをデータとして渡すだけです。これにより、保存する必要がある重要なデータを保存することで、デーモン自体を停止または再ロードできます。

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を使用したい場合、あなたは読むことができますこのファイル

読める対応するドキュメントの「詳細ユニットファイル」セクションを参照してください。このファイルまた。デーモンが応答を停止した場合は、まだ死んでいないかのように、あなたの場合と似ています。

おすすめ記事