Scalar DB入門

こちらの記事では、Scalar DBの概要とそのトランザクションプロトコルである「Consensus Commit」について説明しました。本記事では、Java言語を用いたScalar DBの使い方について説明します。

サンプルアプリケーション

今回は説明のために、サンプルアプリケーションとしてシンプルなECサイトを作っていきます。Scalar DBは、ACIDトランザクション機能を持たないNoSQL等のデータベース上でACIDトランザクションを実現する機能を持っているので、それを用いてCassandra上でECサイトを構築します。

今回のサンプルアプリケーションはScalar DBを説明するためのものですので、エラー処理や認証処理等は割愛していますのでご了承ください。

また、本サンプルアプリケーションのソースコードや設定ファイル等は以下にありますので、実際に実行してみたい方はこちらをご覧ください。

https://github.com/scalar-labs/scalardb-samples/tree/main/scalardb-sample

スキーマ

サンプルアプリケーションのスキーマは以下のようになります。

ER図

すべてのテーブルは sample ネームスペース内に作成されます。

customers テーブルは、ECサイトの顧客情報が格納されています。credit_limit カラムはその顧客のクレジットカードの利用上限額で、credit_total カラムはその顧客の現在のクレジットカードの利用額になります。

orders テーブルは、注文情報が入っているテーブル(注文内でどの商品をいくつ購入したか)で、statements テーブルは注文明細情報が格納されているテーブルです。最後に item テーブルは商品情報が入っているテーブルとなります。

トランザクション

今回は、以下のトランザクションを実装します。

  1. 顧客情報の取得
  2. 注文の発行。注文はクレジット決済で行われます。その際には、その顧客のクレジットカードの上限額のチェックを行います
  3. クレジット返済。クレジット利用額を減算します

アプリケーション作成手順

ここからは、実際にサンプルアプリケーションを作成する際の手順を説明します。

Step 1. 設定ファイルを作成する

まず、データベースに接続するための設定ファイル(ここではファイル名はdatabase.propertiesとします)を作成する必要があります。今回はCassandraをローカルホストに立ち上げることを想定しています。設定ファイルは以下のようになります。

database.properties

今回は、デフォルトの設定であるConsensus CommitをIsolation levelをSnapshot Isolationとして使うので、それらの設定は入れていません。

Step 2. スキーマを作成する

次に、スキーマを作成します。Scalar DBではスキーマを作成するためにSchema Loaderというツールを使います。Schema Loaderは以下のGitHubのリリースページからダウンロードすることができます。今回はScalar DB 3.6.0を使います。

https://github.com/scalar-labs/scalardb/releases

ダウンロードが完了したら、スキーマを定義するためのスキーマファイル(ここではファイル名はshema.jsonとします)を作成します。スキーマファイルはJSON形式で記述されます。本記事では、Scalar DBのデータモデリング関しては触れませんが、そちらに関してはまた別の機会に紹介したいと思います。スキーマファイルは以下のようになります。

schema.json

スキーマファイルを作成したら、以下のようにSchema Loaderを実行し、スキーマを作成します。

# java -jar scalardb-schema-loader-3.6.0.jar --config database.properties --schema-file schema.json --coordinator --replication-factor 1

Schema Loaderの詳細については以下をご覧ください。

https://github.com/scalar-labs/scalardb/blob/master/schema-loader/README.md

Step 3. トランザクションを実装する

Scalar DBのJavaライブラリはMaven Centralに上がっています。GradleやMavenから使う場合は以下のように依存を指定します(今回はScalar DB 3.6.0を使っています)。

Gradle

Maven

依存が指定できたら、トランザクション実装の準備が整いました。

トランザクションマネージャのインスタンスの作成

まず、Scalar DBでトランザクションを実行するためにトランザクションマネージャのインスタンスを作成する必要があります。以下のコードでトランザクションマネージャ (DistributedTransactionManager) のインスタンスを作成する事ができます。ここではStep 1で作成した設定ファイルを指定してトランザクションマネージャのインスタンスを作成しています。

トランザクションの実装

先程作成したトランザクションマネージャのインスタンスを用いてトランザクションの実装を行います。

1. 顧客情報の取得

顧客情報の取得のトランザクションは以下のようになります。

Scalar DBでは、トランザクションを開始しコミットするまで、複数のCRUDオペレーションを実行することができ、それらはアトミックに実行されます。そして、CRUDオペレーションの実行中に何らかのエラーが発生した場合は、トランザクションをアボートする必要があります。Scalar DBにおける例外の取り扱いに関しての詳細は以下のドキュメントをご覧ください。

https://github.com/scalar-labs/scalardb/blob/master/docs/api-guide.md#handle-exceptions

また、トランザクションがリードオンリーの場合もコミットが必要となることに注意してください。

2. 注文の発行

注文の発行のトランザクションは以下のようになります。placeOrderメソッドの引数として、顧客ID(customerId)と、どの商品を注文するか(itemIds)、そしてそれらの商品をいくつ注文するか(itemCounts)があります。

このトランザクションでは、複数のテーブルに対して読み込みと書き込みを行っています。Scalar DBを用いずにこれらの書き込み処理をCassandraに対して行うと、途中で処理が失敗したときに不整合な状態になってしまう可能性があります。また、同様にScalar DBを使わない場合、複数の注文処理を同時に行ってしまうと、クレジット利用上限金額を超えた注文が成立してしまう可能性があります。

3. クレジット返済

クレジット返済のトランザクションは以下のようになります。

このトランザクションは、customersテーブルから現在のクレジット利用額を取得し、返済額分を減算しています。このトランザクションに関しても、Scalar DBを使わない場合、複数同時に実行されると、あるトランザクションが別のトランザクションの更新を打ち消してしまうロストアップデートが発生する可能性があります。

まとめ

本記事では、ECサイトの例を用いてJava言語を用いたScalar DBの使い方について説明し、ACIDトランザクションを用いない場合に発生する問題についても議論しました。

本記事で紹介した方法以外にも、gRPCを用いて実装されたScalar DB ServerやGraphQL(商用ライセンス)を用いる方法もあります。gRPCやGraphQLは言語に依存しないテクノロジーなので、Java言語以外からScalar DBを使うことも可能です。また、SQLを用いてScalar DBを操作する方法も現在開発中です。これらについては、また別の機会に紹介できればと思います。

--

--