この投稿では、systemdを使用してマルチターミナルアプリケーションを実装する方法について説明します。
要約:サービステンプレートとターゲットを使用して、いくつかのサービスインスタンスを起動します(「ワーカー」の実装)。 PartOf依存関係。 ユニットの[インストール]セクションについて少し。
エントリー
マルチスレッドが不十分またはまったくない多くのプログラミング言語(Python、Ruby、PHP、非常に多くの場合C / C ++)は、「ワーカー」の概念を使用します。 アプリケーション内のスレッド間の複雑な関係をフレーミングする代わりに、アプリケーションの複数のシングルスレッドコピーを起動します。各コピーは負荷の一部を担います。 SO_REUSEPORTオプションのおかげで、同じポートで一緒にリッスンすることも可能です。これは、ワーカー(実際には、APIを実装するかWebサイトを提供する通常のサーバーアプリケーション)が必要なタスクのほとんどをカバーします。
ただし、このアプローチには、コピーの起動、ステータスの監視、エラーの処理、あらゆる種類の停止/リロードの終了などを行う「スーパーバイザー」が必要です。 些細に見えるが、これは完全に些細な作業ではなく、ニュアンスに満ちている(たとえば、ワーカーの1人がTASK_UNINTERRUPTIBLEになった場合、またはSIGSTOPを受け取った場合、あまりよく書かれていない親で再起動すると問題が発生する可能性がある)。
スーパーバイザーなしで起動するオプションがありますが、この場合、リロード/再起動タスクは管理者に転送されます。 「コアあたり1プロセス」モデルでは、24コアサーバーでサービスを再起動することが自動化の候補になります。そのため、同じSIGSTOPおよびその他の複雑なニュアンスをすべて処理する必要があります。
この問題の1つの解決策は、systemdサービステンプレートを一般的なターゲットへの依存とともに使用することです。
理論
パターン
systemdは、サービスを起動するための「テンプレート」をサポートしています。 これらのテンプレートは、コマンドライン引数の任意の場所に挿入できるパラメーターを受け入れます(man systemd.service)。 パラメーターは、サービス名の「@」記号を介して渡されます。 「@」の後(ただしポイントの前)の部分は「インスタンス名」と呼ばれ、%iまたは%Iによってエンコードされます。 パラメーターの完全なリストはwww.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiersです。 サービス名(ドットの前)に「@」が存在することは、これがテンプレートであることを示しています。
最も単純なテンプレートを作成してみましょう。
/etc/systemd/system/foobar-worker@.service
[単位] 説明=フーバー番号%I [サービス] タイプ=シンプル ExecStart = / bin / sleep 3600%I
そして、これらのいくつかを実行します:
systemctl start foobar-worker @ 1 systemctl start foobar-worker @ 2 systemctl start foobar-worker @ 300
私たちは見ます:
ps aux | grep sleep ルート13313 0.0 0.0 8516 748? SS 17:29 0:00 /ビン/スリープ3600 1 ルート13317 0.0 0.0 8516 804? SS 17:29 0:00 /ビン/スリープ3600 2 ルート13321 0.0 0.0 8516 764? SS 17:29 0:00 /ビン/スリープ3600 300
ここで、それらすべてを何らかの方法で共通の方法で開始したいと思います。 これにはターゲットがあります。
対象
ターゲットは何もしないsystemdユニットですが、依存要素として使用できます(ターゲットは複数のサービスに依存することも、サービスはターゲットに依存することもできますが、これもサービスに依存します)。
ターゲットの拡張子は.targetです。
最も簡単なターゲットを書きましょう:
vim /etc/systemd/system/foobar.target
[単位] Wants=foobar-worker@1.service foobar-worker@2.service Wants=foobar-worker@300.service
(.serviceに注意してください、必要です!)
「欲しい」については少し話をします。
これで、3つのfoobar-workersをすべて同時に実行できます。
systemctl start foobar.target
(ターゲットへの注意-.serviceの場合は省略でき、.targetの場合は-no)。
プロセスリストに3つのスリープが表示されました。 残念ながら、systemctlがfoobar.targetを停止させても、それらは消えません。 彼らは「労働者」にあまり似ていません。 ターゲットとワーカーを何らかの形で単一の全体に結合する必要があります。 このために、依存関係を使用します。
依存関係
Systemdは、必要なものを正確に記述するための広範な依存関係のセットを提供します。 このリストの「PartOf」に興味があります。 その前に、私たちは望みを使用しました。
それらの動作を比較します。
Wants(使用した)-言及されたサービスは、メインユニットが起動すると開始しようとします。 上記のサービスがクラッシュするか、開始できない場合、これはメインサービスに影響しません。 メインサービスがシャットダウン/再起動した場合、依存関係に記載されているサービスは影響を受けません。
PartOf-前述のシャットダウン/再起動の場合、メインサービスもシャットダウン/再起動します。
必要なものだけです。
ワーカーの説明に依存関係を追加します。
<pre> [単位] 説明=フーバー番号%I PartOf = foobar.target [サービス] タイプ=シンプル ExecStart = / bin / sleep 3600%I
それだけです systemdにfoobar.targetを停止させると、すべてのワーカーが停止します。
依存関係のインストール
systemdのもう1つの興味深い機能は、インストールの依存関係です。 Sysv-initにはサービスを有効/無効にする機能がありましたが、そこで有効にする方法を説明するのは非常に困難でした。 ランレベルは何ですか? 依存関係
systemdでは、すべてが単純です。 「enable」コマンドを使用すると、[install]セクションで指定した内容に応じて、サービスが(スライスメカニズムを介して)「追加」されます。 便宜上、WantedByの依存関係があります。これは、意味的にはWantedの反対です。
私たちがしがみつくことができる標準的なターゲットがたくさんあります。 以下にそれらの一部を示します(すべてsystemd.specialです)。
* multi-user.target(「開始の必要性」の標準、sysv-initの最終ランレベルに相当)。
* default.target-マルチユーザーのエイリアス
* graphic.target-X'ovの起動の瞬間
multi-user.targetにフックしましょう。
新しいコンテンツfoobar.target:
[単位] Wants=foobar-worker@1.service foobar-worker@2.service Wants=foobar-worker@300.service [インストール] WantedBy = multi-user.target
ここで、有効にした場合:
#systemctl enable foobar.target シンボリックリンク/etc/systemd/system/multi-user.target.wants/foobar.targetを作成→/etc/systemd/system/foobar.target。
すべてのサービスは、複数のワーカーからまとめられ、全体として開始/再起動する準備ができており、コンピューター/サーバーの起動時に起動されます。