k8sに基づくアルゴリズムトレーニングシステムの実装(アーキテクチャ案+実装計画)

プロジェクトの背景

科学研究、教育、およびトレーニングの過程で、xx大学のプロジェクト管理と制御、人員調整、進捗管理、タスク割り当て、リソース割り当て、データ分析、および成果管理のニーズを満たすために、統合されたプロジェクト調整を提供します実践的な教育のためのビッグデータ収集、データクラウドソーシングサービス、データクリーニングとガバナンス、データ分析プラットフォーム、およびその他の一般的に使用されるワークベンチでは、一連のシステム管理、プロジェクト管理、コース管理、アルゴリズム開発、データクラウドソーシングを構築する必要があります。教育、科学研究、実践的なトレーニングのための統合プラットフォームとしての文献クエリ、承認管理、および学術サークル。

アルゴリズムトレーニングシステム

序章

アルゴリズム トレーニングは、このシステムのコア機能の 1 つです. ディープ ラーニング アルゴリズム トレーニング プラットフォームをユーザーに提供し、さまざまな一般的なデータ セットを組み込み、コード プログラミングとグラフィカル プログラミングをサポートします. コードは 3 つの言語をサポートします: python, scala r. プログラミング コードを書かずに、部品のドラッグ&ドロップとパラメータの選択だけでモデリングを完了し、アルゴリズムのトレーニングを開始するこのプログラミング手法は、開発者の敷居を大幅に下げ、開発効率を向上させます。

機能要件

  1. アルゴリズム トレーニング タスクの作成
  2. コードのオンライン ライティング (R、Scala、Python 言語をサポート)
  3. アルゴリズム モデルを視覚的に構築する
  4. アルゴリズム モデルが準拠していることを確認する
  5. アルゴリズム モデルのグラフィカル ビューをコード ビューに変換できます。
  6. アルゴリズム トレーニング タスクをオンラインで実行する
  7. コードの実行ステータスと実行ログを監視できます
  8. エラスティック コンピューティング パワー スケジューリング
    • 実行順序、最大実行回数など、アルゴリズムタスクを配置できます。
    • サーバー リソースを自動的にスケジュールして、アルゴリズム タスクの実行環境を提供できます。
    • 各アルゴリズム タスクは最大のリソースを使用でき、最大実行時間は制御可能です。
    • タスクの実行によって消費される最大リソースを制限できます
    • アルゴリズムの実行後、コンピューティング リソースを自動的に再利用できます。

非機能要件

  1. セキュリティ: ユーザー プログラムの操作リソースとシステム権限は制限する必要があります。つまり、ユーザー プログラムの実行時間、メモリ、CPU、およびスレッド数はすべて制限されており、システムに損傷を与えることはできません。

責任

下図は簡単な実行ロジック図で、ユーザーがコードを送信すると、サーバー クラスタ内に独立したマシンが作成され、そのマシン上でコードが実行されます。0

要するに、私の責任は、サーバー リソースを柔軟にスケジュールして、タスク実行のための環境を提供し、タスク実行を調整することです。

画像-20221013164651872

デザインのアイデア

このシステムは oj (オンライン判定) システムに似ています. 実行ロジックはユーザーのコードを送信することです. クライアントはユーザー コードをサーバーに http 経由で送信し, サーバーはコードを評価マシン上で実行して実行結果を返します.結果。ユーザーが提出したコードは必ずしも安全ではなく、無限のプロセスを作成したり、ファイルを消費して評価マシンのリソースを消費したり、リモート サービスへの接続を確立したりして、攻撃者にバックドアを提供する可能性があります。サーバーのセキュリティを確保するために、ユーザー プログラムとシステム コールが使用するリソースを制限する必要があります。

リソースの制約

プログラムが実行できるリソースを制限するとは、メモリ、実行時間、プロセス数、スレッドなどのリソースを制限することです。通常、 setrlimit () を使用して完了します。

setrlimit() 関数は C の関数です。具体的な使用方法については、https://blog.csdn.net/u012206617/article/details/89286635 を参照してください。

システムコール制限

入出力、プロセスの作成、システム情報の取得など、プログラムのシステム関連のすべての操作には、システム コール (System Call) が必要です。システム コールを制限すると、システム ディレクトリ構造の取得やシステム権限の取得など、プログラムの危険な動作を制限できます。システムコールを制限しないプログラムをサーバや他のプログラムと併用すると、システムのセキュリティや他のプログラムの動作に支障をきたす場合があります。

現在、システムコールを制限するために一般的に使用されている 2 つのスキームは ptrace() と seccomp です. 前者の原則は、ターゲットプログラムがシステムコールをしようとするたびにメインプログラムに通知することです. 危険なシステムであることが判明した場合コールすると、プログラムは時間内に強制終了されます。ptrace() は、システム コールごとに 2 つの割り込みを生成します (システム コールに入る前に 1 つ、システム コールが戻った後に 1 つ)、これは効率に影響します。

seccomp (フル ネーム セキュアコンピューティング モード) は、Linux カーネルでサポートされているセキュリティ メカニズムです。Linux システムでは、多数のシステム コール (システムコール) がユーザー モード プログラムに直接公開されています。ただし、すべてのシステム コールが必要なわけではなく、システム コールを悪用する安全でないコードがシステムにセキュリティ上の脅威をもたらす可能性があります。seccomp を使用して、プログラムが特定のシステム コールを使用するように制限します。これにより、システムの露出を減らすと同時に、プログラムを「安全な」状態にすることができます。

ptrace()使用されている評価システムは: HustOJ , UOJです;seccamp使用されているは: QDUOJ , TJudgerです。

Docker ベースのサンドボックス

プログラム実行のリソースやシステムコールをコーディングで制限するには、複雑なロジック処理が必要であり、ユーザープログラムとWebサーバーを同時に実行すると、依然として大きなセキュリティリスクがあります. システムのセキュリティを確保する別の考え方も考えられます.サンドボックス (SandBox) 環境を形成するためのシステム環境。

サンドボックスとは?

サンドボックスは仮想システム プログラムを指し、それによって提供される環境は実行中の各プログラムから独立しており、既存のシステムには影響しません。実際、Java 仮想マシン jvm は使用されるサンドボックス メカニズムです。

Docker は、開発者がアプリケーションと依存関係を軽量でポータブルなコンテナーにパッケージ化できるオープン ソース アプリケーション コンテナー エンジンです. コンテナーは、コンテナー間のインターフェイスなしでサンドボックス メカニズムを完全に使用します.

一連の考え

ユーザー プログラムを実行するたびに Docker コンテナーを作成し、入力データとユーザー プログラムを渡し、コンテナーでプログラムを実行し、監視スレッドを作成し、プログラムの実行状態を監視し、特定の出力ディレクトリは、外部の世界でマウントできます

Docker のミラーリング テクノロジは、さまざまな言語に対応する動作環境を提供できます。

実行環境が必要な言語 (Python やその他のスクリプト言語など) では、システムのライブラリ ディレクトリをコンテナーにマップすることができます. セキュリティに関しては、ユーザー プログラムも同様に実行されるため、通常は考慮する必要はありません。ディレクトリには書き込み権限がなく、ライブラリ ディレクトリには読み取り可能な構成ファイルなどの機密情報はありません。

Docker が提供するネットワーク機能を使用して、コンテナー内のターゲット プログラムをネットワーク化することもできます。

リソース制限については、 Docker が提供するリソース制限を使用できます

長所と短所

アドバンテージ:

  • リソース制限機能を完了するために独自のコードを記述する必要はありません。Docker が提供するリソース制限を直接使用できます。

  • コンテナーは、より高いセキュリティのために互いに分離されています

  • システムコールを制限する必要はありません

欠点:

  • コンテナーの作成にはある程度のオーバーヘッドが必要であり、各実行にはさらに約 1 秒かかることがテストされています。

このシステムの場合、深層学習アルゴリズムのトレーニング自体に時間がかかるため、コンテナー作成の時間オーバーヘッドは基本的に無視できます。

画像-20221013171745497

考慮すべき問題

  1. サーバーはクラスターを使用していますが、作成した docker はどのように管理すればよいですか?

  2. ユーザープログラムの実行が終了した後に docker リソースを再利用する方法は?

  3. クラスター環境では、docker は必要なリソースをどのようにマウントしますか (docker が配置されているマシンは、リソース マシンと同じマシン上にない場合があります)。

  4. プログラムの実行状況をリアルタイムで監視するには?(失敗、成功、実行中)

k8s ベースの docker コンテナの配置

実際、上記の問題の本質は、マシン間でコンテナーを管理する問題、つまりコンテナー オーケストレーションを解決することであり、これにはオープンなコンテナー オーケストレーション サークルで非常に人気のあるテクノロジであるk8s ( Kubernetes ) について言及する必要があります。アプリケーションのデプロイ、メンテナンス、拡張メカニズムなどの機能を提供する Google の大規模コンテナ管理システム borg. のソース バージョン。

Kubernetes の概要

Kubernetes は、多層セキュリティ保護、アクセス メカニズム、マルチテナント アプリケーション サポート、透過的なサービス登録、サービス検出、組み込みの負荷分散、強力な障害検出と自己修復メカニズム、およびサービス ローリングをサポートする、完全な分散システム サポート プラットフォームです。アップグレードとオンライン拡張、スケーラブルなリソース自動スケジューリング メカニズム、多粒度リソース クォータ管理機能、開発、テスト、展開、運用および保守の監視を含む包括的な管理ツール、ワンストップの完全な分散システム開発およびサポート プラットフォーム。

k8s は、ポッドを最小のスケジューリング単位としてコンテナーを配置するために使用しコンテナーはポッドにカプセル化されますPod は 1 つ以上のコンテナーで構成されている場合があり、これらのコンテナーは同じライフ サイクルを持ち、ノード全体でまとめて調整されます。環境、ストレージ ボリューム、および IP 空間を共有します。

通常、ポッドを直接作成することはありませんが、k8s コントローラーにポッドの作成と管理を任せます。**コントローラーでは、ポッドのデプロイ方法、コピーの数、実行する必要があるノードなどを定義できます。さまざまなコントローラーにはさまざまな特性があり、さまざまなビジネス環境に適しています. 一般的なコントローラーには、**Deployment、DaemonSet、Job、CronJob、StatefulSet およびその他のコントローラーが含まれます。**以下は、いくつかのコントローラーの該当するシナリオです。

  1. 展開: ステートレス サービスの展開に適しています

  2. StatefulSet: ステートフル サービスの展開に適しています

  3. DaemonSet: 展開されると、いくつかの典型的なアプリケーション シナリオなど、すべてのノード ノードが展開されます。

    クラスタ ストレージ デーモンを実行します。たとえば、各ノードで実行します。

    各ノードでログ収集デーモンを実行する

  4. ジョブ: タスクを 1 回以上実行する

  5. CronJob: 定期的またはスケジュールされた実行タスク

k8s はリソース管理とスケジューリングの方法を提供します. テンプレート ファイルにパラメータを設定するだけで、ポッドのコンピューティング リソース、外部参照リソース、およびリソース オブジェクトを制限できます。

k8s について詳しく知りたい場合は、非常に完全な公式ドキュメントを読むことができます。

実装のアイデア

上記の紹介に基づいて、一般的な実装のアイデアを形成できます。ユーザー プログラムを実行するたびにポッドを作成し、リソースをポッドにマップし、ポッドでユーザーのプログラム コードを実行するだけで済み、コンテナー オーケストレーションについて考える必要はありません。

前述のように、Pod の作成は一般的にコントローラーによって処理されますが、一般的に使用される 5 つのコントローラーの特性を理解すると、Job コントローラーがビジネス ニーズに最も適したコントローラーであることは間違いありません。ジョブ コントローラの詳細を紹介しましょう。

ジョブ コントローラーは、次の 3 種類のタスクを実行できます。

  • 1 回限りのタスク: 通常、1 つの Pod のみが開始されます (Pod が失敗し、Pod 作成の失敗が再起動し続ける場合を除きます)。Pod が正常に終了すると、Job が完了します。
  • 連続タスク: タスクを連続して数回実行します。前のタスクが完了すると、すべてのタスクが実行されるまで次のタスクが実行されます。
  • 並列タスク: 複数のタスクを同時に同時に実行します。

注: ここでの複数のタスクのシリアルおよびパラレル実行とは、同じタスクを複数回実行することを指します。

ビジネスのニーズに応じて、最適なのはワンタイム タスクを使用することです.ユーザーがプログラムを実行するたびに、ワンタイム タスクを実行するジョブ コントローラーを作成し、ポッドにユーザー プログラムを実行させます.プログラムが完了すると、ポッドが終了し、ジョブが完了します。spec.ttlSecondsAfterFinishedタスクの実行が完了してから一定時間待ってからジョブを削除するようにパラメーターを設定することもできます。(通常、実行ログなどを確認する必要があるなど、ある程度の時間を確保する必要があります)。

画像-20221013170406401

リソースの制約

リソース制限に関しては、前述のように、docker が提供するリソース制限メソッドを使用すると、k8s でのリソース管理とスケジューリング メソッドも提供されます. テンプレート ファイルにパラメーターを設定するだけで、Pod コンピューティング リソース、外部参照リソース、リソース オブジェクトを制限できます。使用例は次のとおりです。

resources: #资源限制和请求的设置
 limits: #资源限制的设置
 	cpu: String #CPU的限制,单位为CPU内核数,将用于docker run --cpu-quota 参数;
 	#也可以使用小数,例如0.1,它等价于表达式100m(表示100milicore)
	memory: String #内存限制,单位可以为MiB/GiB/MB/GB,将用于docker run --memory参数,
 requests: #资源请求的设置
 	cpu: String #CPU请求,容器刚启动时的可用CPU数量,将用于docker run --cpu shares参数
 	memory: String #内存请求,容器刚启动时的可用内存数量

しかし、現時点では未解決の問題が 2 つあります。

  1. リソースサーバーとk8sクラスターサーバーは別物ポッド内のプログラム動作に必要なリソース(ユーザーコードなど)へのアクセス方法
  2. コードの実行ステータスを監視する方法

コンテナ間のデータ保存と共有の問題を解決

最初の質問についてまずお話しさせてください.dockerではマウントを使用してホストファイルをコンテナーにマップしますが、k8sは独自のストレージボリューム(ボリューム)の抽象化を定義し、それらが提供するデータストレージ機能は非常に強力です. 構成によってポッドにデータを注入できるだけでなく、ポッド内のコンテナー間でデータを共有することもできます。異なるマシンの Pod では、ストレージ ボリュームを定義することでデータ共有を実現できます。

k8s のストレージ ボリュームは、主に 4 つのカテゴリに分類されます

  • ローカル ストレージ ボリューム: 主に Pod 内のコンテナ間のデータ共有、またはデータ ストレージと Pod と Node 間の共有に使用されます
  • ネットワーク ストレージ ボリューム: 主にデータ ストレージと、複数のポッドまたは複数のノード間の共有に使用されます
  • 永続的なストレージ ボリューム: ネットワーク ストレージ ボリュームに基づいて、ユーザーはストレージ ボリュームによって使用されるストレージ システムを気にする必要はありませんが、消費する必要があるリソースの数を定義するだけで済みます。
  • 構成ストレージ ボリューム: 主に各 Pod に構成情報を注入するために使用されます。

このシステムによって選択されたネットワーク ストレージ ボリューム nfs は、次の理由に基づいています:

  1. プロバイダーが実行される複数のマシンがあります。つまり、データ ストレージを共有するには複数のノードが必要です。
  2. ストレージクラスの構成が複雑すぎるため、ネットワーク ストレージ ボリュームを使用することで要件を満たすことができます。
  3. 同社のサーバーレス運用・保守、k8sクラスターの構築・運用は全て1人で完結 永続ストレージはストレージシステムの利用者とプロバイダーを切り離すだけなので、利用する必要はありません。

ネットワーク ストレージ ボリューム

ここで、ネットワーク ストレージ ボリュームの概念に言及する必要があります: ネットワーク ストレージ ボリュームは、複数のポッドまたは複数のノード間のデータ ストレージおよび共有の問題を解決することです. k8s は、NFS /iSCSI などの多くのクラウド プロバイダーの製品およびネットワーク ストレージ ソリューションをサポートします/GlusterFS/RDB/flocker など

このシステムは、NFS (ネットワーク ファイル システム)ネットワーク ファイル システムを使用します。これにより、ネットワーク内のコンピューターは TCP/IP ネットワークを介してリソースを共有できますNFS を介して、ローカル NFS クライアント アプリケーションは、ローカル ファイルにアクセスするのと同じように、NFS サーバー上のファイルを直接読み書きできます

リソース サーバーをサーバーとして使用し、k8s クラスター サーバーをクライアントとして使用するだけでよく、ネットワーク ストレージ ボリューム テクノロジを使用して、k8s の Pod がリソース サーバーのディレクトリとファイルを共有できるようにします. NFS は公開されたディレクトリのセキュリティを制限できます構成ファイルを通じて. ホストへのアクセスの制限、読み取りおよび書き込み権限など.

画像-20221013150115011

プログラムの実行状況を監視する

1つ目は、ユーザプログラムの状態をどのように判断するかということです. ユーザプログラムの実行状態は大きく分けて,キューイング中, 実行中, 失敗, 完了の4つの状態に分けられます. 先ほど, 監視スレッドを起動して状態を監視することを述べました.コンテナ内のプログラム

ポッドの寿命のさまざまな段階はフェーズ値に対応し、これらのフェーズ値からユーザー プログラムの実行状態を判断できます。

  • 保留中: Pod は k8s システムによって受け入れられましたが、1 つ以上のコンテナー イメージがまだ作成されていません。たとえば、スケジューリング前のコンピューティング時間や、ネットワークを介したイメージのダウンロードにかかる時間など、これらの準備が原因でコンテナー イメージが作成されません。
  • Running : Pod が Node にバインドされ、すべてのコンテナーが作成されました。少なくとも 1 つのコンテナーがまだ実行中か、開始中または再起動中です
  • 成功: Pod 内のすべてのコンテナーが正常に終了し、少なくとも 1 つのコンテナーが失敗した終了ステータスを示しました。つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了されました
  • 失敗: Pod 内のすべてのコンテナーが終了し、少なくとも 1 つのコンテナーが失敗した終了ステータスを示しました。つまり、コンテナはゼロ以外のステータスで終了したか、システムによって終了されました
  • 不明: 何らかの理由で Pod のステータスを取得できません.これは通常、Pod が配置されているホストの通信エラーが原因です.

ここに問題があります. これはポッドの状態です. ポッドが成功した後, ポッドコンテナで実行されているコードも成功することをどのように判断できますか? つまり, ポッドの成功と失敗の状態はどのように状態に対応していますか.ユーザープログラム? 実際、一言で言えば、「コンテナーはゼロ以外のステータスで終了するか、システムによって終了されます」があり、これは、コンテナがゼロ以外で終了した場合にのみ失敗ステータスが表示されることを意味しますただし、システムがコンテナーを直接終了し、コンテナーを終了させます。次に、コンテナ内のユーザー プログラムの実行ステータスを監視するだけでよく、実行に失敗した場合は、ゼロ以外のステータスでプログラムを終了させます。たとえば、次のシェル コマンド

python run.py
# 判断命令是否执行成功
if [ $? -ne 0 ];then
    echo "================执行失败==============================="
    exit 0;
fi

1 回のジョブ実行で Pod とコンテナーが開始されるため、コンテナーの開始時にのみスクリプトを実行する必要があるため、k8s の Pod の command パラメーターと args パラメーターは、それぞれの起動コマンドと起動パラメーター リストを設定できます。 container. これら 2 つのパラメーターは、必要な効果を実現できます。

注: コマンドと引数の設定は、元の Docker イメージで定義された EntryPoint と CMD をそれぞれ上書きします.使用する場合は、次の規則に注意してください:

  • テンプレートにコマンドまたは引数が指定されていない場合、Docker イメージで定義されたデフォルトが使用されて実行されます。

  • テンプレートにコマンドが指定されていて、引数が指定されていない場合は、指定されたコマンドのみが使用されます。Docker イメージで定義されているデフォルトの EntryPoint とデフォルトのコマンドの両方が無視されます。

  • 引数のみが指定されている場合、Docker イメージで定義されているデフォルトの EntryPoint が、指定された引数と組み合わせて実行されます。

  • コマンドと引数の両方が指定されている場合、Docker イメージで定義されているデフォルトの EntryPoint とコマンドは無視されます。提供されたコマンドと引数が結合されて実行されます。

プログラムの状況はポッドの状況で判断できますが、現時点ではポッドの状況をリアルタイムで監視することはできません

  1. 定期的なポーリング クエリ Pod ステータス
  2. k8s ライフサイクル コールバックを使用する
  3. k8s ウォッチを使用して監視する
Pod の状態を定期的にポーリングする

アイデアはとてもシンプルです. 該当するジョブのステータスを一定期間チェックします.しかし, デメリットも大きいです. 第一に, 遅延が発生します. 第二に, ポーリングは多くのk8sサーバーとWebサーバーを消費します.ジョブが多すぎると、間違いなくサーバーの負荷が大幅に増加するため、お勧めできません。

k8s ライフサイクル コールバックを使用する

k8s には、PostStart イベントと PreStop イベントの 2 つのライフサイクル イベントがあり、コンテナが正常に作成される直前とコンテナが終了する前にコールバックを実行します。

  • PostStart:コンテナーが正常に作成された直後に、イベントがトリガーされ、コールバックが実行されますコールバックでの操作が失敗した場合、コンテナーは終了し、コンテナーの再起動ポリシーに従ってコンテナーを再起動するかどうかが決定されます。

  • PreStop: **コンテナーが終了する前に、イベントがトリガーされ、コールバックが実行されます。** コールバックの実行結果にかかわらず、コンテナは終了します。

コールバックを実装する方法は 2 つあります。1 つは Exec、もう 1 つは HttpGet です。

  • Exec コールバックは、特定のコマンドまたは操作を実行します。Exec によって実行されたコマンドが stdout の結果で OK である場合は実行が成功したことを意味し、それ以外の場合は異常と見なされ、kubelet はコンテナーを強制的に再起動します。
  • HttpGet コールバックは特定の HttpGet リクエストを実行し、返された HTTP ステータス コードによってリクエストが正常に実行されたかどうかを判断します。

コールバック メカニズムを使用して、コンテナーが正常に作成されたときに http 要求を開始し、サーバーにステータスを実行中に変更するよう通知できます。

コンテナーが終了する前に http 要求を開始し、プログラムの実行状況 (失敗または成功) をサーバーに渡し、サーバーに状況を変更するよう通知します。

次の図は、ポッドのライフ サイクル イベント図です。

画像-20221013202125728

質問

この解決策は実現可能ですが、実際の実装プロセスでは、プログラム実行のステータスを get リクエストを介して直接送信することはできず、サーバーには Pod のステータスを照会するように通知することしかできないことがわかりました。しかし、現時点では Pod は停止しておらず、まだ実行中であるため、プログラムが正常に実行されるかどうかはわかりません。しかし後で、pod が停止したときにコンテナーの状態を監視するために watch の非同期使用を有効にして、その後の Pod の状態を監視できるようにすることを考えました。

watch を使用して Pod のステータスを監視する

k8s では、Pod リストなどの Watch インターフェイスを介して、Pod やその他のコンポーネントの状態の変化を継続的に検出できます. Pod の状態が変化した場合は、

kubectl get pod -w   或者--watch

一般的な考え方は、k8s が提供する javaClient を使用してウォッチを呼び出し、ポッドのステータスを監視することです (ジョブを作成するとき、ジョブとポッドを一意に識別するためにラベルが使用されます)。 javaClient が k8s の監視 API を呼び出すときに使用するのは OkHttpClient です. 公式の例によると OkHttpClient10s は切断されます. 設定で OkHttpClient のタイムアウト時間を設定できます. タイムアウト時間はあまり長く設定しないでください. 接続が時間内に閉じられないと、k8s apiserver は多くの接続を浪費し、圧力が高くなりますが、短すぎると、プログラムの実行が完了する前に接続が閉じられる可能性があります。

ここで別の質問があります: OkHttpClient のタイムアウト期間を合理的に設定し、プログラムの終了前に接続が閉じられないようにする方法は?

質問

この問題の最初の解決策は、**OkHttpClient のタイムアウト期間をユーザー プログラムの制限時間より少し長く設定することです。**ユーザー プログラムの実行タイムアウトは確実に Pod を破壊するためです。接続が閉じられます。ただし、このシステムはアルゴリズムのトレーニング システムです. **実行時間は一般的に長く、ユーザー プログラムの制限時間は比較的長いです. **このような接続が長時間維持されると、実際には無駄になります.資力。

ライフサイクル コールバック + 継続的なリスナー ステータスの監視

しかし、これを前の戦略と組み合わせて、ポッドの終了前 (この時点でプログラムが実行されている) にポッドの監視を開始すると、接続時間を大幅に短縮できます。そのため、最終的には、ライフサイクル コールバック + ウォッチ モニタリングを組み合わせる戦略を採用しました。

画像-20221014102725472

ここまで、ユーザー プログラムを実行するためのサンドボックス環境の設計と実装のアイデアについて説明してきましたが、まだ解決しなければならない詳細がいくつかあります。

  1. ジョブのジョブ数を制御する方法は?
  2. ユーザープログラムの実行結果をユーザーに表示するには?

ジョブのジョブ数を制御する

単一のユーザー プログラムのリソースを制限するだけでなく、全体として実行されるプログラムの数も制限する必要があります。そうしないと、プログラムを一緒に実行する多くのユーザーがサーバー リソースを使い果たしてしまいます。

一連の考え

ジョブのジョブ数を制限する最も簡単な方法は、実行時に現在実行されているジョブの数を照会し、それが最大数より少ない場合はジョブを作成することです。

画像-20221014110704604

ジョブ数が上限を超えたらどうすればいいのか? 操作に失敗したことをユーザーに直接伝えるのは絶対に良くない. ユーザーのリクエストを格納できるコンテナーを用意し、ユーザーの実行リクエストを入力させた方がよい.キューの状態を確認し、他のプログラムが完了するのを待ち、実行を継続します。このロジックにより、キューのデータ構造を簡単に考えることができます。メッセージ キュー ミドルウェアを使用すると、間違いなくこの問題をうまく解決できます。

具体的なプロセスは次のとおりです。

  • ユーザーはサーバーにリクエストを送信してプログラムを実行し、そのリクエストをコンシューマ キューに直接格納します。

  • リクエストを受け取った後、コンシューマーはまず k8s サーバーにアクセスして、ジョブの数を照会します。

  • 制限を超えずに数量が消費された場合は、k8s サーバーにリクエストを送信してジョブを作成します

  • 制限以上の場合、メッセージはキューの先頭に再格納され、一定期間後に消費されます

画像-20221014140533923

上記の手順で要件を満たすことができますが、まだ最適化できる部分があります.ジョブ数を判断するときは、常にk8sサーバーにアクセスしてジョブ数を照会することを前述しました.ジョブ数がlimit, メッセージ The queue will continue to retry, and each time it will query the number of jobs in k8s, which will undoubtly increase the pressure on the k8s server. 実際には、行く代わりに実行中のジョブの数を手動で維持できます問い合わせるたびにk8sに。redis の基本データ構造文字列を使用してジョブの上限をキャッシュし、ジョブが開始されるたびに 1 を減算し、ジョブが破棄されるたびに 1 を追加するだけです。

ただし、ジョブを 1 つ減らすことから、ジョブを作成する要求を開始することまではアトミックな操作でなければならないため、 ここで分散ロックを追加できることに注意してください。ジョブの作成が失敗した場合は、データのロールバックの問題。前に述べたように、ジョブは自動的に破棄されるため、ポッドが失敗または完了したときにジョブの数を維持するためにポッドを監視する必要があります。

実行結果のユーザーへの通知方法

**ユーザー プログラムの出力は特定のディレクトリに保存される**と前述しましたが、プログラムの出力をユーザーに知らせるにはどうすればよいでしょうか。

これには 2 つのオプションがあります。

  1. websocket を使用して、長い接続を確立し、定期的にログ ファイルを読み取り、ログをリアルタイムで出力します。
  2. クライアントにログの内容を直接リクエストしてもらい、リクエストするたびに最新のログを確認できます。

このシステムのプログラムは一般的に時間がかかるため、長時間接続を確立するには接続を維持するための多くのリソースが必要です. これまでの開発経験によると、長時間接続を確立すると、ネットワークの変動などにより切断されやすくなります.プログラムログにはリアルタイム性が要求されないことを考慮して、2 番目のソリューションが採用されます。

minio オブジェクト ストレージ

ログとコード ファイルのストレージ システムも、ある程度設計されています。

このシステムには、オープンソース オブジェクト ストレージ プロジェクト minio によって構築された分散オブジェクト ストレージ システムを使用する特定のリソース サーバーがあります。minio 設計の主な目標は、プライベート クラウド オブジェクト ストレージの標準ソリューションになることです。主に、大量の写真、ビデオ、ドキュメントなどを保存するために使用されます。写真、動画、ログファイル、バックアップデータ、コンテナ/仮想マシンのイメージなど、大容量の非構造化データの保存に最適です。

ビルドの具体的なプロセスについては、ブログを参照してください https://blog.csdn.net/R1011/article/details/124399434

また、nfs を使用して k8s クラスター サーバーとリソース サーバーを接続し、リソース サーバーのディレクトリを k8s クラスターと共有することも前述しました.ユーザーのコード ファイルを minio のリソース ディレクトリにアップロードし、それを共有します。ユーザーのコード ディレクトリは、実行時にデータ ボリュームを介してマップされます. 同時に、起動時に特定のユーザー ログ ディレクトリをマップするためのデータ ボリュームが必要です. プログラムが実行されると、ログはこのディレクトリに出力されます.が実行されているため、ログをリソース サーバーに同期できます。クライアントがプログラム ログを照会するときは、minio を介してログ ファイルに直接アクセスするだけで済みます。

要約する

最後に、図を使用して、このアルゴリズム システムのアーキテクチャを要約します。

画像-20221014154441257

おすすめ

転載: blog.csdn.net/qq_45473439/article/details/127326736
おすすめ