top pageへ.

Programming Room.

Google Cloud Tips.

Batch. 2024/04/01

 Batchはバックエンドで長時間動作するバッチジョブを実行するためのプロダクトです。


おしながき

概要.

 Batchは2022/10/11にリリースされた新しいプロダクトです。日本で使えるようなったのは東京リージョンが2023/04/11大阪リージョンが2023/07/07です。ドキュメントに日本語が用意されたは2024年になってからだったでしょうか、つい最近です。


 Batchは一時的かつ長時間動作するバッチジョブを実行するために使用します。webアプリケーションではフロントエンドをGAEで、バックエンドをBatchで実装することが可能になり、この組み合わせだけでもおおかたのアプリケーションは構成が可能と思われます。GAEには2013年時点ですでに提供終了していたbackendsというその名のとおりバックエンドを実装するための機能がありましたが、その代替えとしてのCloud Runジョブには稼働が最大24時間までという課題があります。BatchはGCEのマネージドインスタンスグループで実行されるので、長時間の実行も可能なバッチジョブにふさわしいプロダクトとなっています。


 Batchの存在目的としてはCloud Runジョブと同じです。また同じことはGCEで自分でVMインスタンスを起動・終了させれば実現可能です。これらとの違いを簡単に比較したのが以下の表です。

  Batch Cloud Runジョブ GCE VMインスタンス
実行対象
  • Dockerコンテナ
  • スクリプト
  • GCEのインスタンステンプレート
 Dockerコンテナ
  • VMインスタンス
  • インスタンステンプレート
  • etc.
キュー あり あり なし
エラー時の再実行 あり あり なし
SpotVMの利用 可能 不可 可能
起動時間 70〜110秒 10秒前後 30〜60秒

 キューやエラー時の再実行の仕組みは「ジョブの作成と実行の概要」に記載されていますが、文字ばかりなので理解しにくいです。仕様はCloud Runジョブと同等と思われるので、そちらを参照したほうが図解されていてわかりやすいと思います。

 Cloud Runジョブより優れている点として、SpotVMを利用して実行することもできます。SpotVMはデータセンターの余剰リソースを利用して実行する仕組みで、利用料金が通常のVMの1/3程度と非常に安いのが魅力です。その代わり常に使えるわけではなく、また稼働中にデータセンターの都合で停止させられる可能性もあります。停止後に再起動してやり直すとか、再起動後に続きから実行できるようにアプリケーションを構成する必要があります。

 起動時間はCloud RunジョブやGCEのVMインスタンスと比べると、より長くかかります。小さめのリソースで作ったhelloworldを起動するケースでも、Dockerコンテナで70秒くらい、インスタンステンプレートで110秒くらいでした。Cloud RunジョブはPodの起動相当と思われお手軽に起動しますが、Batchは起動用のディスクをその場で作ってノードを起動する相当と思われるので、時間がかかるようです。

 料金は、実行に利用したGCEのリソースと同じです。Batch独自の価格設定はありません。


実行対象と実行方法.

 Batchで実行内容を実装する実行対象には、以下の種類があります。

  1. Dockerコンテナ
  2. スクリプト
  3. インスタンステンプレート

Dockerコンテナ.

 コンテナはGKE/Cloud Runと同じように用意し、Artifact RegistoryやContainer Registoryに格納します。Cloud Runのために用意したコンテナイメージをそのまま実行することも可能でした。コンテナイメージの準備については、ここでは説明しません。
 Container Registoryに格納されたコンテナイメージの実行は、「基本コンテナジョブを作成する」に記載されているとおりです。コンテナイメージはRunnable.Container.Builder.setImageUri()メソッドで指定します。それを実行するVMインスタンスは、ComputeResourceAllocationPolicy.InstancePolicyの2つで指定します。この2つは矛盾がないように選択する必要があるようです。
 このスニペットでジョブが作成され、キューに入ります。非同期実行なので、まだジョブは実行されていません。


スクリプト.

 スクリプトはLinuxのシェルスクリプトです。スクリプトの実行は「基本スクリプトジョブを作成する」に記載されているとおりです。
 シェルスクリプトのみで実行できる物は限られますし、上記の公式ドキュメントに説明されているようにapt等でインストールするにしても実行時では効率が悪くなります。シェルスクリプトのみで実現できる程度のものを実行するためだけにVMインスタンスを起動するのも、もったいない気がします。なのでここではこれ以上説明しません。 


インスタンステンプレート.

 インスタンステンプレートは、GCEでVMインスタンスを起動するための、インスタンスのテンプレートです。Batchがリリースされた直後にはインスタンステンプレートもコンテナ/スクリプトと同列に紹介されていたのですが、ドキュメントに日本語が追加された時点では説明が消えていました。しかし機能的には抹消されたわけではなく残っています。
 インスタンステンプレートの実行は「Compute Engine VM インスタンステンプレートを使用してジョブを作成する」に記載されています。


 インスタンステンプレートは、あらかじめ用意しておく必要があります。存在しないインスタンステンプレートを指定してもこのスニペットは実行可能ですが、もちろん何も実行されません。
 またインスタンステンプレートはGCPコンソールからでも作れますが、GCPコンソールから作れるのはインフラのリソースを指定しただけのもので、実行すべき何かが含まれていません。これでは前記のスクリプトのケースと同じになってしまいます。そのためインスタンステン/プレートは「確定的なインスタンステンプレート」であることが望ましいです。確定的なインスタンステンプレートの作り方についてはGCEの話題になるので、こちらのページにまとめました。


インスタンステンプレートとスクリプトとの違い.

 Batchの仕組みとしては全く同じです。スクリプトの実行との違いはAllocationPolicy.Builder.addInstances()に渡すAllocationPolicy.InstancePolicyOrTemplateの値で、以下の部分です。


スクリプト:
GCEのマシンタイプを指定する。
      // Policies are used to define on what kind of virtual machines the tasks will run on.
      // In this case, we tell the system to use "e2-standard-4" machine type.
      // Read more about machine types here: https://cloud.google.com/compute/docs/machine-types
      InstancePolicy instancePolicy =
          InstancePolicy.newBuilder().setMachineType("e2-standard-4").build();

      AllocationPolicy allocationPolicy =
          AllocationPolicy.newBuilder()
              .addInstances(InstancePolicyOrTemplate.newBuilder().setPolicy(instancePolicy).build())
              .build();

インスタンステンプレート:
作成済みのインスタンステンプレート名を指定する。
      // Policies are used to define on what kind of virtual machines the tasks will run on.
      // In this case, we tell the system to use an instance template that defines all the
      // required parameters.
      AllocationPolicy allocationPolicy =
          AllocationPolicy.newBuilder()
              .addInstances(
                  InstancePolicyOrTemplate.newBuilder().setInstanceTemplate(templateLink).build())
              .build();

 そのため、インスタンステンプレートでもスクリプトを使用できます。


インスタンステンプレートでスクリプトを使用する.

 VMインスタンスでジョブを実装すると、実装したモジュールを起動する処理も必要になります。そのモジュールの起動をスクリプトで行うことができます。「基本スクリプトジョブを作成する」のスニペットでは、以下の部分です。このスニペットでは"echo"でメッセージを表示しているだけですが、コメントにあるように直接実行ファイルを指定して実行することもできます。

      // Define what will be done as part of the job.
      Runnable runnable =
          Runnable.newBuilder()
              .setScript(
                  Script.newBuilder()
                      .setText(
                          "echo Hello world! This is task ${BATCH_TASK_INDEX}. "
                              + "This job has a total of ${BATCH_TASK_COUNT} tasks.")
                      // You can also run a script from a file. Just remember, that needs to be a
                      // script that's already on the VM that will be running the job.
                      // Using setText() and setPath() is mutually exclusive.
                      // .setPath("/tmp/test.sh")
                      .build())
              .build();

SpotVMを利用する.

Dockerコンテナの場合.

 GCEのマインタイプを指定する際に AllocationPolicy.InstancePolicy.Builder.setProvisioningModel(ProvisioningModel.SPOT) を追加します。


インスタンステンプレートの場合.

 インスタンステンプレートの作成時に以下の引数を指定します。つまり標準VMとSpotVMでインスタンステンプレートを作り分ける必要があります。

--provisioning-model=SPOT

ジョブ名の指定.

 CreateJobRequest.Builder.setJobId() メソッドで作成するジョブにジョブ名を設定するとこができます。このメソッドの名前はIDでAPIリファレンスにも「ID」と説明されていますが、このメソッドが実際に設定するのはジョブ名です。ジョブにはジョブ名とは別にUIDが存在します。
 ジョブは実行の終了から60日後に自動的に削除されますが、終了したジョブは実行の履歴として残っているだけです。作成しようとするジョブの名称が、既に存在しているとジョブの名称と同じだと、新たなジョブの作成に失敗します。使いたい名前と同じ名前のジョブが存在するなら、作成前に削除する等の対応が必要になります。
 ジョブ名を指定しない場合、job-921716a0-3d3c-4a95-8e01-5f6d95b8b93a みたいな名称でジョブが作成されます。そのためジョブ名を指定せずにジョブを作成すると、60日後に自動的に削除されるまで放置することも可能になります。しかし何のジョブなのか後から見てもわからなくなるので、実行終了後も残しておくのなら、被らないように名前を決めるのが最善となります。


VMで使用するOS.

 インスタンステンプレートの場合はVMインスタンスを作成する際にOSを選択しますが、自由に選択できるわけではありません。安全に実行するためには「ジョブのVMのOS環境の概要」に書かれているOSを選択する必要があるようです。結局使えるのは以下のようですが、最低限の選択肢は用意されていると思います。Ubuntu LinuxがないけどRocky Linuxでいいか。


使い分け.

コンテナとインスタンステンプレート.

 コンテナもインスタンステンプレートも同じようにプログラムを実行できますので、その使い分けについて疑問が湧きます。すでにコンテナ/インスタンステンプレートが用意出来ているならそれを使いまわすのが簡単でしょう。ユーザから見えないところで動作するバックエンドですので、起動時間の違いは気にする必要もありません。


BatchとCloud Runジョブ.

 起動時間以外に大きな違いは価格です。矢印の左が公式ドキュメントに記載の価格、右が下記条件で計算した時間当たりの価格です。

Cloud Run Batch (GCE)
無料枠 CPU : 180,000vCPU秒/月 → 24時間とちょっと
メモリ : 360,000GiB秒/月 → 24時間とちょっと
なし
vCPU $0.00002400/vCPU秒 → $0.1728/時間 $0.028026/vCPU/時間 → $0.056052/時間
メモリ $0.00000250/GiB秒 → $0.036/時間 $0.003739/GB/時間 → $0.014956/時間

 簡単にするため、条件は以下に揃えています。


 比較してみるとCloud Runって結構高い... 何か計算間違ってないか不安になります。無料枠で収まらないようなら、Batchで実装したほうが良さそうです。
 ただしGCEの価格はインスタンスの起動・終了の時間も課金されるのですが、インスタンステンプレートから起動した場合、どこからどこまで課金されるのか不明です。起動にかかる110秒のすべてではないと思うのですが、起動・終了があまりにも頻繁だと損になります。そこそこの頻度でそれなりの時間動作し続けるようならBatch、そうでないならCloud Runジョブという使い分けもできそうです。

BatchとGCE.

 VMインスタンスとの比較だと起動時間はもちろん、キューやエラー時の再実行等の機能性でBatchの方が勝っています。GCEは最もプリミティブなIaaSなので当然ですが。


▲page top.
Copyright 2005-2024, yosshie.