はじめに
Java でクラウドネイティブなアプリケーションを作るとき、以前は「起動が遅い」「メモリを使う」「サーバーレスに載せるとコールドスタートが気になる」といった印象がありました。
その前提を変えてくれる選択肢が Quarkus です。
この記事では、IBM Enterprise Build of Quarkus の魅力を伝えるための題材として、AWS Lambda で動く雨量監視システムを作った例を紹介します。
※生成AIのIBM Bobを使い制作しています。
ポイントは次の3つです。
- Java のまま AWS Lambda に載せられる
- 起動が軽く、サーバーレスと相性がよい
- 常時起動サーバーを減らせるので、監視系ワークロードのコストをかなり抑えられる
今回のサンプルコードはこちらです。
IBM Enterprise Build of Quarkusとは
IBM Enterprise Build of Quarkus は、Quarkus をエンタープライズ用途で使うための IBM 提供ビルドです。
IBM の製品ページでは、Quarkus を「高速起動」「低メモリ」「クラウドネイティブ」「AI/クラウド時代向けの Java フレームワーク」として位置づけています。
参考:
- https://www.ibm.com/products/enterprise-build-of-quarkus
- https://developer.ibm.com/articles/introducing-ibm-enterprise-build-quarkus/
Quarkus 自体の特徴は、実行時ではなくビルド時にできるだけ多くの処理を済ませる点です。
従来の Java アプリケーションでは、起動時にクラスパススキャン、DI コンテナ構築、自動設定、リフレクション処理などが多く発生します。Quarkus はこの負荷をビルド時へ寄せることで、起動時間とメモリ使用量を抑えます。
これは AWS Lambda のようなサーバーレス環境と非常に相性がよいです。
なぜLambdaなのか
雨量監視のような処理は、常に大量のリクエストを受け続けるタイプのシステムではありません。
今回の例は、Web API として常時リクエストを待ち受ける構成ではなく、一定間隔で起動して処理し、終わったら止まるバッチ型の Lambda として考えています。
たとえば、次のような処理です。
- 5分ごとに気象庁 API から雨量データを取得する
- 台風接近時だけ監視頻度を上げる
- しきい値を超えたら通知や保存を行う
- 通常時はほとんど待機している
このようなワークロードを EC2 などの常時起動サーバーで動かすと、処理していない時間にも料金が発生します。
一方、AWS Lambda なら、基本的には実行回数と実行時間に応じた課金になります。監視処理のように「短時間だけ定期実行する」処理では、かなり安くできます。
作ったもの
今回のリポジトリは、2つのアプリケーションで構成しています。
-
aws-lambda-rainfall/- 気象庁 API から雨量データを取得する Lambda 側
- 取得したデータを API サーバーへ送信する
-
quark01-rainfall-api/- 雨量データを PostgreSQL に保存する Quarkus REST API
- 河川水位データ API も持つ
- 簡易 dashboard を提供する
構成イメージは次の通りです。
EventBridge Scheduler
|
v
AWS Lambda (Quarkus)
|
| HTTP
v
Quarkus REST API
|
v
PostgreSQL
サンプルでは API 側も Quarkus で作っています。Lambda 側と API 側の両方を Java / Quarkus で揃えられるため、チームの技術スタックを分散させずに済みます。
Lambda側の実装
Lambda 側は quarkus-amazon-lambda を使います。
pom.xml には次の依存関係を入れています。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-amazon-lambda</artifactId>
</dependency>
REST Client も Quarkus の拡張で扱います。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-reactive-jackson</artifactId>
</dependency>
設定は application.properties にまとめています。
quarkus.lambda.handler=rainfall
quarkus.rest-client.jma-api.url=https://www.jma.go.jp/bosai
quarkus.rest-client.quark01-api.url=${QUARK01_API_URL:http://localhost:8080}
quarkus.rest-client.quark01-api.headers.Authorization=Bearer ${QUARK01_API_TOKEN:dummy-token-for-dev}
ここで重要なのは、API サーバーの URL やトークンをソースに直書きしないことです。
実環境では Lambda の環境変数として QUARK01_API_URL と QUARK01_API_TOKEN を設定します。
Native Imageにするか、JVMモードで動かすか
Quarkus を Lambda に載せるときは、JVM モードで動かす方法と、Native Image にして動かす方法があります。
Native Image の主なメリットは、起動が速く、メモリ使用量を抑えやすいことです。
Lambda ではコールドスタートが発生するため、起動が速いことはそのまま体感性能に効きます。また、メモリ使用量を抑えられれば、より小さいメモリ設定で動かせる可能性があり、コスト面でも有利になることがあります。
一方で、Native Image にはデメリットもあります。
- ビルド時間が長くなりやすい
- GraalVM やコンテナビルドなど、ビルド環境の準備が必要になる
- リフレクション、動的クラスロード、一部ライブラリの扱いで追加設定が必要になることがある
- Apple Silicon Mac で直接 native build すると、Lambda 用 Linux バイナリではなく macOS 用バイナリになる点に注意が必要
特に最後の点は重要です。
AWS Lambda で必要なのは Linux 用のバイナリです。Apple Silicon Mac 上で直接 native build すると、基本的には macOS 用 arm64 バイナリが生成されるため、そのまま Lambda では動きません。
Lambda 向けに Native Image を作る場合は、Linux 環境、CI、またはコンテナビルドを使って Lambda で動く形式にする必要があります。
mvn package -Dnative -Dquarkus.native.container-build=true
今回の記事では、まず IBM Enterprise Build of Quarkus / Quarkus を Lambda に載せる価値と、バッチ型ワークロードでのコスト感を伝えることを主眼にしています。
そのため、Native Image は「より起動速度とメモリ効率を詰めたい場合の選択肢」として扱い、最初は JVM モードで動かして構成を確認し、その後 Native Image 化を検討する流れが現実的です。
API側の実装
API 側は Quarkus REST + Hibernate ORM with Panache + PostgreSQL です。
雨量データは次のような REST API で扱います。
POST /api/rainfall
GET /api/rainfall
GET /api/rainfall/latest
GET /api/rainfall/alerts
河川水位データ用には次の API を用意しています。
GET /api/river
GET /api/river/{id}
POST /api/river
DELETE /api/river/{id}
永続化は Panache Entity で簡潔に書けます。
@Entity
@Table(name = "rainfall_records")
public class RainfallRecord extends PanacheEntity {
@Column(nullable = false)
public String location;
@Column(nullable = false)
public Integer hourlyRainfall;
@Column(nullable = false)
public Integer total24h;
@Column(nullable = false)
public Integer forecast1h;
@Column(nullable = false)
public LocalDateTime timestamp;
@Column(nullable = false, updatable = false)
public LocalDateTime createdAt = LocalDateTime.now();
}
DB は PostgreSQL です。
ローカル検証用には docker-compose.yml を用意しています。
cd quark01-rainfall-api/docker
docker-compose up -d
コスト感
雨量監視のような定期実行バッチでは、Lambda の「使った分だけ課金」が効きます。
たとえば、5分間隔で実行する場合を考えます。
- 1時間あたり 12 回
- 1日あたり 288 回
- 30日で 8,640 回
仮に 1 回の処理が 2 秒、メモリ 256MB で済むなら、実行時間はかなり小さくなります。
台風接近時だけ 1 分間隔に上げても、追加で発生する実行回数は限定的です。
常時起動の VM では「待機している時間」にも料金がかかります。Lambda では、待機時間は基本的に課金対象ではありません。
このため、今回のような次のワークロードでは Lambda が特に向いています。
- 定期実行バッチ
- 通常時は低頻度、異常時だけ高頻度になる監視
- 短時間で完了するデータ取得・判定・保存処理
Quarkus は起動が軽いため、こうした Lambda の性質を活かしやすいです。
IBM Enterprise Build of Quarkusで伝えたい価値
このサンプルで伝えたいのは、単に「Lambda に Java を載せられる」という話ではありません。
より重要なのは、Java の開発体験を保ったまま、クラウドネイティブで低コストな実行基盤に載せられるという点です。
IBM Enterprise Build of Quarkus の魅力は、次のようなところにあります。
- Java チームが既存スキルを活かせる
- Quarkus の高速起動・低メモリの恩恵を受けられる
- JVM モードと Native Image の選択肢を持てる
- Kubernetes / OpenShift / serverless などのクラウドネイティブ環境へ展開しやすい
- エンタープライズ利用で重要なサポートやライフサイクルを期待できる
従来の Java アプリケーションサーバー型の考え方では、アプリケーションごとにサーバーやコンテナを常時起動しがちです。
しかし、すべての処理が常時起動に向いているわけではありません。
今回の雨量監視のような処理は、定期実行バッチに分解しやすく、サーバーレス化の効果が出やすい領域です。
注意点
実運用では、以下の点に注意します。
秘密情報をソースに入れない
API URL、トークン、DB パスワード、SSH 接続情報、固定 IP などは GitHub に含めません。
今回のリポジトリでも、実環境値は .env や Lambda 環境変数で扱う前提にしています。
本番では認証をきちんと設計する
サンプルの dashboard では、ログイン値を CHANGE_ME にしています。
本番で使う場合は、Cognito、OIDC、API Gateway Authorizer、あるいは社内 IdP などと組み合わせて認証を設計する必要があります。
コストはログや周辺サービスも含めて見る
Lambda 本体の実行コストは非常に小さくできます。
一方で、CloudWatch Logs、DB、通知、API Gateway、NAT Gateway などを使う場合は、それらの費用も含めて見積もる必要があります。
特に NAT Gateway は構成によっては固定費が大きくなるため、低コスト構成では注意が必要です。
まとめ
IBM Enterprise Build of Quarkus の魅力は、Java をクラウドネイティブ時代の実行モデルに合わせやすくする点にあります。
今回の雨量監視システムでは、次のことを確認できます。
- Quarkus で AWS Lambda 向けの Java アプリを作れる
- REST API や DB 保存も Quarkus でまとめられる
- 定期実行・監視系ワークロードは Lambda と相性がよい
- 常時起動サーバーを避けることで、コストをかなり抑えられる
- 企業向けには IBM Enterprise Build of Quarkus のサポートやライフサイクルが価値になる
Java は重い、サーバーレスには向かない、という印象はもう固定観念になりつつあります。
Quarkus と Lambda を組み合わせると、Java のまま軽く、速く、安く動かす構成を選べます。
そして、その選択肢をエンタープライズで採用しやすくするのが IBM Enterprise Build of Quarkus です。
今回は、まず一番わかりやすい 定期実行バッチ型 の例として紹介しました。
では、API Gateway と組み合わせた Web API 型や、外部サービスから呼ばれる Webhook 型でも同じ考え方は使えるのでしょうか。
この点は次回、別の記事で整理します。
参考リンク
- IBM Enterprise Build of Quarkus
https://www.ibm.com/products/enterprise-build-of-quarkus - Overview of IBM Enterprise Build of Quarkus
https://developer.ibm.com/articles/introducing-ibm-enterprise-build-quarkus/ - Quarkus AWS Lambda Guide
https://quarkus.io/guides/amazon-lambda - サンプルリポジトリ
https://github.com/TSA0001/31-quarkus-aws01