ExecStop構文なしでサービスデーモンを正常に終了するにはどうすればよいですか?

ExecStop構文なしでサービスデーモンを正常に終了するにはどうすればよいですか?

私はシステム初心者です。

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

serviceDaemonMongodbなどのコマンドがサービスを正しく終了しない理由を知りたいです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)制御グループに関連するいくつかの微妙な部分がありますが、マニュアルを読んで詳細を学ぶことができます。

自分が作った問題に戻って:

  1. Type=と がなければ、BusName=サービスは次のようになります。シンプル
  2. 欠席ExecStop=、一つシンプルSIGTERM信号をサービスに送信し(おそらく)、サービスが終了するまで90秒待ちます。そしてその子プロセス。
  3. 失敗した場合、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"タイムアウトしました。殺す。

2つのメッセージ間の経過時間は正確に90秒です。このサービスはSIGTERMを受信したときに停止するように設計されていないようです。 2 行目は、内部システムの状態が 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つのクローンに分岐します(2)。ソースが終了し、成功ステータスが systemd に返されます。 2番目はまだ実行中であり、主な長期実行デーモンです。伝統的にファイルシステム<servicename>.pidの下にファイルを作成します/runが、systemdは通常そのファイルなしで分岐したプロセスを見つけます。 1つを保存すると、設定を介してシステムに場所を知らせますPIDFile=。そのままにすると、systemdはそれを削除します。このファイルは、「レガシー」init / rcシステムにのみ必要です。Type=このタイプのサービス機能は次のとおりです。分岐。それも提供します今後のスタートマーク体系的に通知するタイプ。他の長期実行タイプはこれを実行できません(使い捨てただし、開始コマンドもできるだけ早く完了する必要があります。

この注文はsystemdに関するものです。確認するサービスが開始されました。起動速度で判断すると、比率はほぼ反対であり、シンプルタイプは最もよく実行されるタイプです。したがって、初期化を完了するために他のサービスがあなたのサービスに依存しないことがわかっている場合は、Fastを選択してください。それ以外の場合は、最も有益なものを選択してください。分岐または通知する、これはシステムの起動時間に最大の影響を与えることに注意してください。

関連情報