Windows Azure Storage Service を用いた在庫管理の設計

https://social.msdn.microsoft.com/Forums/ja-JP/windowsazureja/thread/b76f647b-5e11-446b-92bd-2efdc2e7e362

Azure フォーラム に質問があった在庫管理の設計例を題材にしたWindows Azure Storage Service(主にKVS)による設計例をここで考えていきたい。問題の詳細は上記のリンクを参照してください。

1. 商品在庫管理テーブル

商品コード

商品名

在庫エリアコードAREA01在庫数

在庫エリアコードAREA02在庫数

在庫エリアコードAREA03在庫数

1

液晶テレビ

7

0

0

2

テレビラック

3

0

0

3

7.1chオーディオ

0

0

100

商品在庫管理テーブルを定義します。在庫エリアがこの問題では3箇所になっていますが、より多くの在庫エリアコード(倉庫)があって、商品に必要な属性数との和がAzureテーブルのプロパティ数の上限数(255以内*)に達してしまう場合は、在庫エリアコード毎に商品の在庫管理テーブルを作り、それらから商品毎にまとめた在庫数を管理する集計用の在庫管理テーブルを用意して、注文処理ではその集計用のテーブルを使い在庫を引き当てるようにします。各在庫エリアコードの在庫管理テーブルと集計用の在庫管理テーブルはeventual consistencyで変更を伝搬します。

* https://msdn.microsoft.com/en-us/library/dd179338(v=MSDN.10).aspx

注文処理では、この在庫管理テーブルの商品から在庫量を読み取り、必要な注文数が確保できるかどうかを確認します。必要な注文数が確保できるならば、その注文数を在庫量から減らして在庫管理テーブルを更新します。更新するとき楽観的同時制御(optimistic concurrency)を使い、同一商品の在庫がこの注文処理中に更新があったかどうかをチェックします。もし、同一商品の在庫がこの注文処理中に変更したときは、再度、同一商品の在庫数を読み取り注文数が確保できるかどうかを確認して再処理を試みます。なお、複数の在庫エリアコードのうち、注文数を満たすためにどこの在庫エリアコードを使うかなどのロジックはここでは考えません。

在庫管理テーブルはこのように注文により減算される一方、倉庫における入庫(新規の補填や返品などによる)によって在庫量が増加します(棚卸などでの欠損やその他の理由により倉庫オペレーションで在庫が減ることは例外事項としてここでは考えません)。倉庫オペレーションによる在庫量の増加も同じ在庫管理テーブルに対して注文と同じように更新を行います。更新の際の楽観的同時制御の利用により、入庫処理中に注文があり、在庫数が減産される場合は再度、再処理を試みます。

Webアプリケーションでのカタログの在庫数の表示の変更は、注文での在庫の引当てが成功し在庫管理テーブルの更新された後、また、入庫により在庫管理テーブルの更新が成功した後に表示の変更を行います。

注文および入庫は在庫管理テーブルの非正規化(RDBの第1正規化相当)により、1行に対する更新操作なので操作の実行はACIDトランザクションで保護されます。しかし、ここでの問題は、

(a) ある注文処理中の、別の注文処理、入庫処理の割り込み

(b) 入庫処理中に、(複数の)注文処理の割り込み

にあります。これを楽観的同時制御で解決しています。

2. 注文テーブル

注文コード

注文日時

会員コード

会員名

商品コード

商品名

注文数量

取引単価

小計

在庫エリアコード

在庫エリアコード...

注文テーブルを定義とします。1回の注文で複数の商品の注文があったときはそれぞれを1行に分けて挿入します。ここでも基本はRDBの第1正規化です。注文コードをPartitionKeyとすれば、各注文明細はRowKeyにして同一の物理サーバに配置されるので、同一の注文が別の物理サーバに配置されないようにしておくのがいいでしょう。また、同一PartitonKeyを使うことで明細を構成する複数の行を一括して挿入するEntity Groupトランザクションが利用でき性能が向上します(1操作100行まで)。一方、注文の集計用としては、この注文テーブルをそのまま使うよりは、別に集計用に注文テーブルを用意するのがいいでしょう(後述のCommand and Query Responsibility Segregationの一種)。集計用の注文テーブルではPartitionKeyを会員の分類毎、在庫エリアコード毎、注文日毎など、分析の次元毎に用意しておきます。集計用の注文テーブルの作成は、注文データの挿入と同時に集計用の注文データを挿入するため、worker roleのqueueに入れて非同期に処理してもいいですし、後にバッチ的にworker roleを動かして注文テーブルから集計用の注文テーブルを作成してもいいです。いずれしても、集計結果は注文状況をリアルタイムに反映していなくてもよいのでqueueを使った非同期処理の適用な可能です。

3. トランザクションのアーキテクチャ

注文処理では、在庫引当て、決済処理、注文の挿入、出荷処理をこの順序で行います。

最初の在庫引当て(1の処理)で在庫が確保できなければ注文は在庫量不足により受け付られませんので在庫量の変更はありません。在庫の引当てが成功すれば、次に決済処理を行います。決済処理は、外部の決済サービスへのqueueを使った送信を行います。送信が完了すればqueueのトランザクションにより確実に相手に届いていることが保証されます。後は決済サービスの責任範囲ですので、残高不足などは決済サービスの資金回収方法がカバーしてくれるでしょう。次は注文の挿入(2の処理)です。これもWindows Azure Storage Serviceのtableへの行の挿入だけですので、確実に成功するまでリトライすれば実行可能です。最後の出荷処理も、基本的には出荷のためのメッセージ送信をqueueに対して行うだけです。ここでも、出荷はeventualに処理されるでしょうし、もし何らかのエラーが発生したなら、倉庫に対してオペレータが電話などで指示を行えば対応可能でしょう。

4. その他のアーキテクチャ、分析設計上の考慮

上記の設計では2つの点で考慮が必要です。

(a) 実行の配置に関する原則: Windows Azureでいうworker roleの配置の決定法、あるいは、他のパブリッククラウド(Google、Amazonなど)を含めてアプリケーションアーキテクチャの決定法です。これは、Command and Query Responsibility Segregation (CQRS) patternと呼ばれるアーキテクチャです。これは以下のリンクで述べられているものです。

https://vepexp.microsoft.com/techedjapan09/ (LiveIDによるサインインが必要)

複数の依存関係のあるデータ間での実行時の変更の伝搬に関する原則となるアーキテクチャです。

(b) データ定義に関する原則: Windows Azure Storage ServiceのtableはいわゆるKVS(Key Value Store)です。KVSでの非正規化の原則は、上記にあるように、関係モデルにおける第1正規化相当です。また、データ分析設計段階では、「もの」「こと」を識別していきます。複雑なデータの間の依存関係がある場合は、従来の「もの」-「こと」-「もの」などのデータパターンに加えて、高度な分析設計手法が必要となります。今回の在庫管理の例では、それほど複雑な例ではありませんが、高度な分析設計手法として、「高階述語論理」による分析設計法がクラウドのKVS/no SQLでは有効であると考えています。詳細は、以下を参考としてください。

https://www.microsoft.com/japan/events/techdays/2010/session/session.aspx

「T1-401 クラウド コンピューティングのデータ、アプリケーション、開発手法のメタ アプローチ」(2010年4月中の公開予定)

また、「もの」「こと」分析に関しては「アーキテクトの審美眼」が参考となります。

この原則は、複数の依存関係のあるデータ間での設計時の変更の伝搬を解決します。