見出し画像

【kintone】楽観排他制御でも在庫管理がしたい! ~パート1~

みなさま、排他制御してますか? むっずかしいですよね。

プログラムでセマフォを作って排他するか、データベースのrevisionで楽観排他するか・・・。いずれにしてもアプリケーションレベルで難しい処理を要求されますね。

私はふだんkintoneを利用してシステム開発を実施していますので、サーバーサイドのアプリケーションレベルで処理が組めません。そして楽観排他制御・・・つまり、処理が全部終わった後で、成功だったか失敗だったか、判明するという世界で仕事をしています。

kintoneで在庫管理するのはめっちゃ難しいです。

なぜなら、在庫管理には厳密な数の管理と同時操作性が必須だからです。

そのため、クライアントサイドでの楽観排他制御しか利用できない世界では特有の問題が発生します。その説明をしてみようという試みです。

この記事は、「システムはこうあらねばならない!」という記事ではありません。システムはいろんな文脈から生まれてくるもので、そうなった理由を正しく認識しないと、是非の判断はできないからです。戦争反対!

あくまでも、一理論としてとらえてくださいね。

そして間違っている内容がありましたら、やさしく教えていただけるとうれしいです!


楽観排他制御とは

楽観排他制御とは排他制御のうち、データ資源をロックせず、更新処理時に実行の成否を応答する方式のことです。逆は悲観排他制御となります。

「何か起こるのは嫌だから、あらかじめ対象を押さえておくぜ。」が悲観排他で、「何にもなければうまくいくからさ。何かあったらあとで教えるわ!」が楽観排他です。

悲観的な排他制御
楽観的な排他制御

楽観排他制御は、データをロックしないので、同時操作性に優れています。悲観排他制御は先にデータをロックするので、確実にデータの更新処理ができます。

さて、kintoneはリビジョンを採用しているので、楽観排他制御できますが、レコードを更新用にロックすることはできないので、悲観排他制御ができません。

駄菓子屋さんの在庫を管理する

さっそく在庫管理のシステムの構成を考えてみましょう。駄菓子屋さんの在庫管理を考えてみます。
どんなデータを考えますか? 

1)在庫マスタ
2)入出庫台帳

入庫、出庫、在庫修正が起こるたび、物の出入りの内容を入出庫台帳に書き、在庫マスタに記録された数を加減する。つまり、在庫マスタには常に計算値(理論在庫)が記録されている

うん。イメージしやすい!

太字は主キー。マスタデータも忘れずに。

これでいきましょう。



楽観排他制御しかできない僕ら

ではこのデータベースへの更新が楽観排他制御しかできないとき、どのような問題が発生するでしょうか。

実際の処理を考えてみましょう。うまい棒が倉庫に20本あります。そこへうまい棒4本が入荷したとき。

1)入庫として、うまい棒(+4)本のデータを登録する。
2)在庫マスタから在庫数(20)をとる
3)在庫数に4を足す(24)
4)在庫マスタを更新する(24)

この状態から
こうなる

楽観排他制御では処理の実行後にしか、成否が分かりません。先にレコードを更新対象として予約しておく(ほかの処理を待たせる)ことはできないわけです。

では2~4の間で、倉庫から売り場へうまい棒が10本出庫(-10)した場合どうなるでしょうか?

この場合、(24)のまま更新されることはありません。この場合、エラーとなります。(kintone勢の方々はrevisionでイメージしやすいですよね。)

この状態から、4個を入庫しようとするが・・・。
先に10個の出庫(輸送)作業の割り込みを受けて・・・
在庫はリビジョンが1から2へ進んでいるため、更新できない。
*逆に、24という間違った在庫数は登録しないで済む。

悲観排他制御の場合、先に在庫レコードをロックするので、更新する手前でエラーないし処理待ちとなります。楽観排他制御の場合は、更新処理を実施して初めて、それが成功するかどうかわかります。いずれにしても、更新したい在庫レコードは排他制御の対象になるでしょう。

もし駄菓子屋さんが1つの倉庫と100の店舗を持っていたとしたら、100店舗からの通信が1つの在庫レコードに集中し、排他を取り合うことになります。

エラーになったときどうするのでしょうか? ユーザーにエラー表示を出すか、1~4を再度実施するか、ということになります。

このエラー時の一連の処理も問題になります。

アプリケーションレベル(つまりサーバー側)で排他されたときの制御処理ができないとすれば、一連の手続きが正常終了するまで通信を繰り返し、結果としてパフォーマンスの問題を引き起こします。また、リクエスト量制限のあるサービスを利用していた場合、上限に達する可能性があります。

もっとすごいパターンもあります。先ほどの入庫処理の個数を間違えた場合です。どうやって修正しましょうか・・・。

問題はどこにあるか

紙で入出庫台帳を付けていた場合、問題なく運用できていたはずです。それは「台帳が必ず物理的に1つ」だったから。です。問題ないのはあくまでも紙の上では、ですが。
しかしWebなど分散型アプリケーションでは、複数の処理を待ち受けることがあり、その待ち受け方の特性はサービスによって異なる。

サーバーロジックが書けるサービスの場合
アプリケーションで処理要求を1列に並べられるかもしれない。
kintoneでは不可能
サーバーロジックが書けるアプリケーションであれば、
エラーのリトライが通信をまたがない
サーバーロジックが用意できない場合、リトライ処理が通信をまたぐ

問題を整理してみましょう。

まず一つは、在庫数を更新するために複数のクライアントからのリクエストに対して、レコードを排他制御する必要があること(同時操作性)でしょう。例えば1クライアント1レコードだったら、排他制御しなくていいわけですから。

そして、エラーのリトライが通信をまたぐということ(クライアントサイドでのエラー処理依存)でしょう。
悲観排他だったら、ロックの獲得まで待ってくれるかもしれませんが、楽観排他なので、とにかく処理を断行して、できたかどうか必ず返してくれる。このときサーバーロジックがないので、リトライのトリガーがクライアントに戻ってくる。

膝を屈するのか

では楽観排他しかできない僕らは在庫管理をあきらめるしかないのでしょうか?

次回は、排他制御をせずに、在庫を正しく管理してみます。

次の記事



この記事が気に入ったらサポートをしてみませんか?