Google Cloud のデータベース ガイド: パート 3 - Cloud Spannerと Cloud Run での Spring Boot を使用した CRUD オペレーション
Google Cloud Japan Team
※この投稿は米国時間 2022 年 7 月 14 日に、Google Cloud blog に投稿されたものの抄訳です。
このブログで説明すること
Cloud Run にデプロイされた Cloud Spanner の DML API を使用して、Java Spring Boot アプリケーション上で CRUD のテストをします。Dockerfile は使用しません。このテストでは、ある住宅地域でのバドミントン コートの予約のユースケースを取り上げます。その理由は、私の住む地域では、利用できるすべてのコートを同じグループの人々が毎日占領してしまうという問題がありました。テストで紹介する予約システムを実装すると、このグループが予約できるのは 1 つのコートを 1 日 1 時間のみになり、予定をとった日だけしか使用できなくなるため、すべての人にコートを使用できる機会が公平に与えられるようになります。子供たちを含め、地域の人たちの利益になります。
Spanner を選ぶ理由
Spring Boot、Jib、Cloud Run での Cloud Spanner の実装の前に、まずは基本を確認してみましょう。Spanner は私の大好きなリレーショナル データベースで、次のような特徴を備えています。
フルマネージド
ミッション クリティカルな RDBMS サービス
外部との整合性、原子性、独立性、耐久性のあるトランザクションを提供
業界屈指の 99.999% の可用性
マルチリージョン インスタンスのサポート
TrueTime 原子時計
透過的かつ同期的なレプリケーション
100% オンラインでのスキーマ変更とメンテナンス
ダウンタイムなしのトラフィック処理
上記すべてに加えてこの他もグローバル スケールで提供
すばらしいですね。一言では言い尽くせません。ここで頭が混乱しそうになるのもわかりますが、ご説明します。すべての特徴を一つひとつ説明したいのはやまやまですが、今回はこのブログのトピックに合わせて 2 つの特に優れた特徴を取り上げます。その他についてはプロダクトのページをご覧ください。
TrueTime
TrueTime は、すべての Google サーバー上のアプリケーションに提供される可用性の高い分散クロックです。
TrueTime により、アプリケーションは単調に増加するタイムスタンプを生成可能です。タイムスタンプ T が生成される前にタイムスタンプ T' が生成された場合、アプリケーションは T' より大きいことが保証された T を算出できます
この保証は、すべてのサーバーとすべてのタイムスタンプにわたって保持されます。Cloud Spanner はこの機能を使用してタイムスタンプをトランザクションに割り当てます
外部整合性
Cloud Spanner は、強整合性、線形化可能性、直列化可能性が統合された卓越したデータベース サービスだと言えるでしょう。
Cloud Spanner が実際にはパフォーマンスや可用性の向上のために複数のサーバー(場合によっては複数のデータセンター)でトランザクションを実行している場合でも、すべてのトランザクションが順次実行されるかのようにシステムが動作します
1 つのトランザクションが完了してから別のトランザクションの commit が開始する場合、クライアントは、2 番目のトランザクションの効果が反映されるという状態に遭遇することはありません
これらの優れた機能の詳細に関するドキュメントは、こちらとこちらでご覧いただけます。
では、そろそろ実装の詳細に入りましょう。ここでは、実装を次の 3 つのパートに分けて説明します。
Cloud Spanner の設定と DDL
Spanner でのデータの変更
Cloud Run での Spring Boot と Cloud Spanner の手順
A. Spanner の設定と DDL
Cloud Spanner で CRUD オペレーションを行う前に、セルフペース ラボやドキュメントで、Cloud Spanner のインスタンス、データベース、テーブルの設定方法および基本的な DDL などを使用した操作方法の詳細を確認してください。
a. Google Cloud コンソールの [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します
b. Cloud プロジェクトに対して課金が有効になっていることを確認します。詳しくは、プロジェクトで課金が有効になっているかどうかを確認する方法をご覧ください
c. プロジェクトに対して Cloud Spanner API を有効化します
d. インスタンスを作成します
e. インスタンス名に、「Test Instance」などの名前を入力します
f. インスタンス ID は、インスタンス名(「Test Instance」など)に基づき自動的に入力されます
g. デフォルトのオプション [リージョン] を保持し、プルダウン メニューから構成を選択します
h. インスタンスの構成により、インスタンスが保存および複製される地理的なロケーションが決まります
i. このテストの場合、[コンピューティング容量の割り当て] では 100 処理ユニットを設定できます
j. [作成] をクリックします。インスタンスがインスタンス リストに表示されます。
k. [Cloud Spanner インスタンス] ページに移動します
l. 作成したインスタンスをクリックして、[データベースの作成] をクリックします
m. DB 名、DB 言語を入力して [作成] をクリックします
n. データベースの [概要] ページの [テーブル] セクションで、[テーブルを作成] をクリックします
o. [DDL ステートメントの記述] ページで、次のように入力します
p. [送信] をクリックすると完了です。このアプリには、トランザクション(予約情報)データを保持するテーブルが必要です
更新が完了すると、次のようなページが表示されます。
B. Cloud Spanner でのデータの変更
Cloud Spanner では次の 3 つの方法でデータを変更できます。
標準 DML
パーティション化 DML
ミューテーション
Cloud Spanner のデータ操作言語(DML)では、INSERT、UPDATE、DELETE のステートメントを使用してデータベース テーブルのデータを操作できます。DML ステートメントを実行するには、クライアント ライブラリ、Google Cloud コンソール、gcloud spanner を使用します。
標準 DML - 標準的なオンライン トランザクション処理(OLTP)ワークロードに適しています。
コードサンプルを含む詳細については、DML の使用をご覧ください。パーティション化 DML - 以下の例のように、一括更新と削除用に設計されています。
定期的なクリーンアップとガベージ コレクション
デフォルト値での新しい列のバックフィリング
コードサンプルを含む詳細については、パーティション化 DML の使用をご覧ください
ミューテーション - 挿入、更新、削除など、データベース内のさまざまな行やテーブルに、Cloud Spanner によってアトミックに適用される一連の操作を表します。
1 つ以上の書き込みを含む 1 つ以上のミューテーションを定義したら、書き込みを commit するためにミューテーションを適用します
各変更は、ミューテーションに追加された順序で適用されます
注: 今回の例では、Spring Boot フレームワークと Spring Data Cloud Spanner モジュールを使用しています。また、SpannerRepository インターフェースを拡張して、Cloud Spanner のデータをクエリおよび変更するすべてのアプリケーション ロジックをカプセル化するようにしています。このインターフェースは、DML クエリメソッドを使用して Cloud Spanner データで CRUD オペレーションを実行します。
C. Cloud Run での Spring Boot と Cloud Spanner
Spring Data Cloud Spanner モジュールは、Spring Framework で構築された Java アプリケーションで Cloud Spanner を使用する場合に役立ちます。
次の図は、このテストのアーキテクチャの概要を示しています。
1. Cloud Shell と Cloud Run の設定
Google Cloud はノートパソコンからリモートで操作できますが、ここでは Cloud Shell(Google Cloud 上で動作するコマンドライン環境)を使用します。
Cloud Shell をまだアクティブにしていない場合は、次の手順に沿って Cloud Shell をアクティブにし、認証が完了していること、プロジェクト ID(このブログのステップ A.1.a. で作成および選択済み)に設定されていることを確認してください。
なんらかの理由でプロジェクトが設定されていない場合は、次のコマンドを実行します。
gcloud config set project <PROJECT_ID>
Cloud Shell から次の Cloud Run API を有効にします。
gcloud services enable run.googleapis.com
注: プロジェクトをブートストラップせず、次のステップを実行しない場合は、Cloud Shell で次のコマンドを実行してプロジェクト リポジトリのクローンを作成できます。
git clone https://github.com/AbiramiSukumaran/spanner-example.git
git clone https://github.com/AbiramiSukumaran/springboot-client.git
2. Spring Boot Java サーバーアプリ(REST API)のブートストラップ
Cloud Shell 環境から次のコマンドを使用して、新しい Spring Boot アプリケーションを初期化およびブートストラップします。
$ curl https://start.spring.io/starter.tgz -d packaging=jar -d dependencies=cloud-gcp,web,lombok -d baseDir=spanner-example -d bootVersion=2.3.3.RELEASE | tar -xzvf -
$ cd spanner-example
リポジトリのクローンを作成しない場合は、このコマンドを使用してください。このコマンドにより、Maven の pom.xml、Maven ラッパー、アプリケーションのエントリポイントとともに、新しい Maven プロジェクトを含む新しい spanner-example/ ディレクトリが作成されます。
pom.xml ファイルに Spring Data Cloud Spanner スターターと必要な他の依存関係を追加します。spanner-example/pom.xml
application.properties で Spanner データベース接続情報を構成します。
spanner-example/src/main/resources/application.properties
アプリをビルドします。./mvnw package
../spanner-example/src/main/java/com/example/demo/Reservation.java
でエンティティ クラスを作成 - Spring Cloud GCP の Spring Data Spanner サポートにより、Spring Data を使用して Java オブジェクトと慣用的な ORM マッピングを Spanner テーブルに簡単に作成できます。
次のコンテンツを含む ReservationRepository クラスを作成します。
spanner-example/src/main/java/com/example/demo/ReservationRepository.java
インターフェースは、Reservation がドメインクラスで String が主キータイプの SpannerRepository<Reservation, String> を拡張します。Spring Data はこのインターフェースを通じて自動的に CRUD アクセスを提供するため、追加のコードを作成する必要はありません。
基本オペレーション(挿入、更新、削除、検索、ID で検索、条件で検索)のための REST Controller を以下のファイルの ReservationController クラスに作成します。
../spanner-example/src/main/java/com/example/demo/DemoApplication.java
アプリケーションを再ビルドして実行します。
./mvnw package
./mvnw spring-boot:run
3. Docker なしでのアプリのコンテナ化
Jib により、Dockerfile / デーモンなしでアプリを最適な方法でコンテナ化し、任意の Container Registry に公開できます
次に進む前に、Container Registry API をアクティブにする必要があります。これは、API にアクセスできるようにするために各プロジェクトに 1 回のみ行う必要があります
$ gcloud services enable containerregistry.googleapis.com
Jib を実行して、Docker イメージをビルドして Container Registry に公開します
$ ./mvnw com.google.cloud.tools:jib-maven-plugin:3.1.1:build \
-Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/<<your-container-name>>
注: このテストでは Jib Maven プラグインを pom.xml で構成していませんが、高度な使用の場合は、より多くの構成オプションのあるプラグインを pom.xml に追加することもできます
Google Cloud コンソールに移動し、ナビゲーション メニューをクリックして [Container Registry] を選択し、イメージが適切に公開されていることを確認します
4. Cloud Run へのデプロイ
次のコマンドを実行して、Cloud Run にコンテナ化されたアプリをデプロイします。
gcloud run deploy <<application>> --image gcr.io/$GOOGLE_CLOUD_PROJECT/<<container>> --platform managed --region us-central1 --allow-unauthenticated --update-env-vars DBHOST=$DB_HOST
–allow-unauthenticated で、認証なしでサービスを届けられるようになります。
–platform-managed とは、Anthos を介した Kubernetes のものではなく、フルマネージド環境をリクエストしていることを意味します。
–update-env-vars では、接続文字列は、環境変数「DBHOST」に渡されることになります。
デプロイが完了したら、コマンドラインにデプロイしたサービスの URL が表示されます。
サービスの URL に接続すると、ブラウザにウェブページと、Cloud Logging の [ログ エクスプローラ] ページにログが表示されます。
生成した Cloud Run URL で REST API にアクセスできるようになりました。
5. Spring Boot Java クライアント アプリのブートストラップ(予約ユーザー インターフェース)
REST API のサーバー アプリケーションと同様に、この Spring Boot フレームワークのクライアント アプリケーションの構造は、リポジトリのクローン作成後は次のようになります。
次の Cloud Shell コマンドを使用してクライアント アプリケーションをブートストラップすることもできます。
$ curl https://start.spring.io/starter.tgz -d packaging=jar -d dependencies=cloud-gcp,web,lombok -d baseDir=springboot-client -d bootVersion=2.3.3.RELEASE | tar -xzvf -
デモフォルダには DemoApplication クラス、Controller クラス、Bean クラスが以下の場所に含まれます。
../springboot-client/src/main/java/com/example/demo/DemoApplication.java
../springboot-client/src/main/java/com/example/demo/MyController.java
../springboot-client/src/main/java/com/example/demo/Reservation.java対応する github ソースリンクは次のとおりです。
MyController.java クラスには、サーバー アプリケーションで作成した REST API を呼び出すメソッド、CRUD HTML ページにルーティングするメソッド、サーバーサイドの検証を実行するメソッドが含まれます。
1. 該当日にそのユニットに既存の予約があるかどうかを検証する API を呼び出すメソッド
validateId(Reservation newReservation)
2. 別のユニットによってその時間がすでに予約されているかどうかを検証する API を呼び出すメソッド
validateSlot(Reservation newReservation)
3. 特定の予約を取得する API を呼び出すメソッド
callReservationsByIdAPI(Reservation reservation)
4. 予約表示の呼び出しで呼び出され、showMessage HTML ページを返すメソッド
showForm(Reservation reservation
5. 検索で呼び出され、searchReservation HTML ページを返すメソッド
searchForm(Reservation reservation)
6. ホームページで呼び出され、HomePage HTML ページを返すメソッド
homeForm(Reservation reservation)
7. CRUD 呼び出しのメソッド
sendForm(Reservation reservation)
processForm(Reservation reservation)
editForm(Reservation reservation)
deleteForm(Reservation reservation)
Thymeleaf は、ウェブ環境とスタンドアロン環境の両方に対応するサーバーサイド Java テンプレート エンジンです。その主な目的は、開発ワークフローに優れたテンプレートを実現することです。つまり、ブラウザに適切に表示され、静的プロトタイプとしても機能する HTML です。これにより、開発チームとのコラボレーションが向上します。
../templates フォルダには、CRUD HTML ページ(ビューレイヤ)用の Thymeleaf テンプレートが以下の場所に含まれます。
../springboot-client/src/main/resources/templates/
GitHub ソースリンク:
https://github.com/AbiramiSukumaran/springboot-client/tree/main/src/main/resources/templatesこのビューレイヤには、クライアント側の検証のためのメソッドも含まれます。
null 以外のフィールドを検証します
予約番号、時間数、プレーヤー人数のデータ形式が適切かどうか入力を検証します
サーバー アプリケーションの pom.xml コンテンツの他に、クライアント アプリケーションの Thyme 依存関係を追加する必要があります
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
以下のステップについては、残りはこのリストのサーバー アプリケーション(セクション C、ポイント 2)と同様です。
ビルドと実行
./mvnw package
./mvnw spring-boot:runDocker なしでの Jib を使用したコンテナ化
$ ./mvnw com.google.cloud.tools:jib-maven-plugin:3.1.1:build -Dimage=gcr.io/$GOOGLE_CLOUD_PROJECT/<<your-container-name>>
Cloud Run でのデプロイ
gcloud run deploy <<application>> --image gcr.io/$GOOGLE_CLOUD_PROJECT/<<container>> --platform managed --region us-central1 --allow-unauthenticated --update-env-vars DBHOST=$DB_HOST
アプリはクラウドに送られるため、ログをご確認ください。デプロイが完了したら、クライアント アプリに URL が表示されます。
URL を開いてアプリケーションで CRUD を実行します。この動画は、選択型のクライアント サイドおよびサーバーサイドの検証による、バドミントン スロットの予約の作成、既存の予約の検索、既存の予約の編集、既存の予約の削除のデモです。

まとめ
Cloud Spanner は、使用の増大に合わせて容易にスケーリングできるフルマネージド リレーショナル データベースを探している企業にとって最適な選択肢です。「処理ユニット(PU)」と呼ばれるきめ細かなインスタンス コンピューティング容量により、通常のインスタンスのわずか 10 分の 1 のコスト(毎月約 $65)で、Spanner でワークロードを実行できます。Spanner のすべての機能とサンプル ユースケースをぜひご覧ください。PostgreSQL 構文に慣れている場合は、PostgreSQL Interface もご利用いただけます。
まとめ
Cloud Run にデプロイされた Docker を使用しないコンテナによる、Spring Boot での Cloud Spanner の簡単なテストはお楽しみいただけたでしょうか。今回のテストから以下の検証を意図的に省いています。練習用として実装してみてください。
スロットが満席のときに新しい予約が作成されないようにするにはどうしたらいいでしょうか。
シングルスとダブルスの選択を尋ねてそれに応じてチームを作成できるように、アプリケーションを拡張するにはどうしたらいいでしょうか。
以下の Codelab を実装にぜひお役立てください。
https://codelabs.developers.google.com/codelabs/cloud-spanner-first-db#0
https://codelabs.developers.google.com/codelabs/cloud-spring-spanner#0
https://codelabs.developers.google.com/codelabs/cloud-kotlin-jib-cloud-run#4
https://codelabs.developers.google.com/codelabs/cloud-run-hello#4
また、LinkedIn でアイデアやご意見・ご感想をぜひお寄せください。
Google、デベロッパー アドボケイト Abirami Sukumaran