[ JJUG CCC 2022 Spring ] AWS Batch × Spring Batch でクラウド最適なバッチを構築した話

こんにちは。[Red Frasco](https://www.red-frasco.com/) でインフラエンジニアをやっている[猪熊](https://twitter.com/sinocloudon)です。
[JJUG CCC 2022 Spring](https://ccc2022spring.java-users.jp/) にて、 [AWS Batch × Spring Batch でクラウド最適なバッチを構築した話](https://fortee.jp/jjug-ccc-2022-spring/proposal/fbb1e886-d51a-4052-b284-6e9c80f132ea) というタイトルで登壇させていただきました。

セッション内容の紹介と登壇のふりかえりをしようと思います。

# セッションの紹介

まずは、セッション内容について紹介します。
アーカイブ動画が公開されました。良ければこちらからご覧ください。
https://youtu.be/ArEY_yIt0GI

## 自己紹介

詳細は割愛します。
香川県出身で、うどんが好きなインフラエンジニアです。

## バッチ基盤を構築する背景

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/c03a987a-94db-4472-c910-c803360823f3.png)

物件情報がポータルサイトに掲載されるまでの一般的な流れを記載しました。

不動産会社の人やシステム連携で受け取った物件情報は、最終的にポータルサイトに表示され、カスタマーはポータルサイトを見て家を探します。
ポータルサイトごとに物件情報を取り込むフォーマットが異なるため、ポータルサイトに物件情報を表示するためには、物件情報の変換が必要です。
各種ポータルサイトの取り込みフォーマットに適した形にデータを変換した上で、ポータルサイトに物件情報を連携する仕組みを**コンバータ**と呼んでいます。

物件情報を管理するシステムからコンバータを経てポータルサイトに物件情報が掲載される。
これが、一般的なフローになります。

**物件情報は複数のシステムから連動され、複数のポータルサイトに掲載されます。
また、これらの物件情報は1日に1回または2回、一括で連携されるケースがほとんどです。
そのため、バッチ処理を組むことで複数のデータ連動処理を効率よく行う必要があります。**

## AWS Batch × Spring Batch 構成の紹介

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/1e6a4514-a06b-ef0e-398b-fa00aa989796.png)

上の図が全体構成です。
大きく、物件情報を受信するバッチと送信するバッチの２種類に分けられます。

* 受信バッチ: FTP で受け取った物件情報を物件管理システムのDBに登録します。
* 送信バッチ: 物件管理システムDBから物件情報を抽出し、FTPでポータルサイトに連携します。

### Spring Batch を選定した理由

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/23edfa10-cadd-ae40-b7e6-8422d9b79e37.png)

前提として、僕たちは業務システムとポータルサイトはシステム特性が異なるものと理解しています。
サイトのレスポンスタイム、素早いリリース、素早い改善といったスピードが求められるSoEの世界と、リリース頻度はポータルサイトほど多くはないが、業務に支障を与えないよう安定的な稼働が求められるSoRの世界に分けて整理しました。

スピード優先のポータルサイトは、Next.js / Node.js を使用して開発しています。
開発言語を統一するメリットももちろんありましたが、我々はあくまでシステム特性に合わせた言語選定をしました。

その結果、物件管理システムでは、エンタープライズシステムでの実績が多く、現在も数多くのミッションクリティカルなシステムを支えている Java を選んでいます。
構築するバッチの数が数十レベルになることが見込まれていたので、Spring Batch を適用して品質を一定に保つことをねらいました。

### AWS Batch を選定した理由

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/a58467a9-7793-a8c2-5ac5-f025ac0acc27.png)

ECS Task でも今回のようなバッチ処理を実現することはおそらく可能だと思われましたが、コンピュートリソースが処理量に応じて自動調整される AWS Batch を選びました。
**リソース調整は1つ1つの小さな運用業務であっても、人数の少ないスタートアップにおいては、それら運用業務をマネージドサービスに委譲することができるということは非常に強力です。**

## バッチ設計・構築にあたっての考慮ポイント

### Step Functions を利用する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/10cb26f4-0935-5746-b304-4984001d6320.png)

Step Functions 経由で AWS Batch を実行することで、 AWS Batch 単体よりも柔軟にバッチジョブをコントロールできるようにしました。
Step Functions と組み合わせるメリットは、バッチジョブをワークフロー化できる点にあると考えています。

* タイムアウト/異常終了したらエラー通知を送信したり、自動リトライを実行したりする
* 仕様変更に応じて、前処理・後処理を追加する
* ジョブの粒度を見直し、ジョブを分割したり、統合したりする

といったように、リトライ制御や構成変更を柔軟に行うことができます。

### Tasklet モデルと Chunk モデル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/56f82ca0-96f2-d128-5a7a-0591e72cc9e8.png)

次に、Spring Batch の使い方について考えました。
Spring Batch には、Chunk モデルと Tasklet モデル、2つの実装パターンがあります。
今回は、 Tasklet をベースにしました。リカバリ運用やジョブ構成をシンプルにできる点を優先しています。

Chunk モデルの考え方は、 Step Functions のジョブフローのベースに適用しました。
Read / Process / Write の3ジョブ構成を基本として、バッチジョブを組むという方針を立てました。

Step Functions を利用すれば、ある程度のジョブフロー化やジョブ制御が可能なので、 Spring Batch 自体はシンプルな　Tasklet をメインに構成しています。

### バッチのリトライ設計

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/39e7ed42-06c2-fd9c-c5cc-6fc51312e506.png)

Spring Batch , AWS Batch , Step Functions それぞれでリトライ設定・実装が可能なので、大枠の方針を決める必要がありました。
結論としては、AWS Batch, Step Functions によるリトライを基本としています。
マネージドサービスの恩恵を最大限活用しつつ、手動でのリトライがコンソールやCLIで簡単にできる点をメリットととらえました。

**また、自動リトライのみを前提にしないようにしています。
特に入力データの不備が多いのですが、何回リトライしても必ず失敗するケースは必ずあります。そのようなイレギュラーな状況に定型化された自動処理は不向きですので、手動リトライの余地を残すようにしています。**

自動・手動、どちらかに倒すのではなく、**最もバッチの安定性を高めることを目的とし、自動と手動をバランスよくミックスさせています。**

### バッチジョブ監視

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/2a05f932-76d6-bf8c-c328-a699f6164344.png)

AWS 標準で取得できるメトリクスでもある程度のシステム観点での監視を行うことはできます。
しかし、当然ながら処理したデータの件数や、どのようなバリデーションエラーが何件発生したのか、といったアプリケーション観点のメトリクスはモニタリング実装をしない限り連携されません。

業務の観点で処理が正常に動いているかどうかを監視することが重要だと考えています。
標準メトリクスに加えて、業務・ビジネス観点で監視すべきメトリクスを決めて、そのメトリクスを監視基盤に連携し、アラートを設定するところまで実施するようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/bdb178c8-13d7-e672-5bdd-955cefee26b0.png)

弊社では、Datadog を使ってバッチの実行監視をしています。
バッチが実行されたら1を立てるというシンプルなモニタリング処理によってバッチが実行されないケースを検知しています。
**ログ監視だけでは、失敗は検知できても実行されていないことは検知できないケースを考慮して、このような監視を実施しています。**

## まとめ

* AWS Batch と Spring Batch を組み合わせたバッチ基盤の事例紹介をしました。
* 本構成がすべてではありません。クラウド上で最適なバッチ構成を考えるきっかけの1つになれば嬉しく思います。
* ジョブ監視・モニタリングは業務・ビジネス観点で見るべきメトリクスを決めた上で監視することが本当に重要だと思っています。

# 登壇のふりかえり

## 御礼

今回、初めてカンファレンスに登壇させていただきました。
カンファレンス運営の皆様や聞いてくれた皆様、本当にありがとうございました。
私自身、非常に良い経験をすることができました。

## オンライン開催

セッションは事前録画、QAのみという形式でのカンファレンスでした。
私はプレゼンテーションをする時、ポイントとなるフレーズだけ決めてあとはその場で話をするタイプなのですが、事前録画だとこのスタイルは非常にやりづらかったです。
スライド1枚1枚に話したい内容をすべて書き出して録画に臨みました。

ちなみに、[こちらの記事](https://qiita.com/okazuki/items/f184c4af44e3fff9fae8) を参考に PowerPoint の機能だけでセッション動画を録画しました。
スライド1枚ごとに撮り直しもできるので、初心者の僕にとっては非常に助かりました。

## ライブ QA

10時からのセッションにも関わらず、時間いっぱい質問に回答することができ、とても嬉しかったです。質問を投げてくれた皆様、ありがとうございました。
特にリトライを中心にバッチの異常系に対してどう対処しているか、という質問が多くあったように思います。

今後も運用していく中で新しいナレッジが蓄積されたら、発信したいと思います。
更新があったら書き換えられる方が良かったので、スライドをそのまま共有せず Qiita に書き写したのはそういう理由でもあります。

## さいごに

今後も会社として、個人として、継続的に発信活動に取り組んでいきたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/310595/98dc2b51-86a2-fda2-ca49-3c4425ea13c8.png)