私たちパクテラ・コンサルティング・ジャパン(以下:パクテラ)は世界基準のナレッジを有し、デジタル領域に強みを持つグローバルカンパニーです。
大規模のプロジェクトを進めていく上で、従業員のボトムアップが常に求められている現状から、社内研修制度の一環としてITのスペシャリストによるセッション「PETS」を開催しております。
本投稿ではその第5回目の内容をレポートさせていただきます。是非、ご一読ください。
PETSとは?
PETSとはPactera Engineer Training Session のそれぞれの頭文字を取ったITのエキスパートを養成するためのパクテラ・ジャパン独自の社内研修です。毎回、外部講師を招待し、日本のDX化を促進させる上での専門性や思考力をセッションを通じて身に付けてまいります。
講師
川島 義隆
株式会社ウルフチーフ 代表取締役
大手SIerで20年間、多数のWebアプリケーション開発プロジェクトのアーキテクチャ設計を担当、また社員教育、技術者採用、研修講師などを努め、2018年10月アーキテクチャ設計専業の株式会社ウルフチーフを創業する。その他、技術コミュニティを中心に登壇多数。
テーマ:排他制御
共有資源に(データやファイル)対して複数のアクセスが見込まれる場合に、同時アクセスによる不具合が生じることを防ぐための排他制御ですが、その必要性や概要について深く理解されている方は少ないのではないでしょうか?今回は、講師の川島さんから排他制御にまつわる基礎的な概要から、実際に現場で活かすことのできるテクニックをレクチャーしていただきました。
1.排他制御にけるコンカレンシー
コンカレンシーとは?
同時アクセスによる不具合を防ぐことが排他制御ですが、この「同時」とは、どのような状態を指すのでしょうか?
上記のように、同時には大きく2つの解釈が存在します。
Concurrent(並行):一つの主体が同時に複数の物事を処理している状態。
Parallel(並列):複数の主体が同時に同じ物事を処理している状態。
同じ「同時」でも主体の個数によって、定義が変わることが分かります。排他制御において、対象となるのはConcurrent(並行)での同時となります。
では実際に、Concurrentに情報を処理し、不整合が生じるケースを見ていきましょう。
ケース①:不整合な書き込み
ユーザーがサイト上にて、様々なタブを開いて、不具合が生じるケースです。タブ間で同一セッションのIDを持ったタブが複数生成され、それぞれのタブに同一のデータが入力され、不整合が生じてしまいます。
ケース②:同じ番号の採番
クライアント(ユーザー)毎に同じIDを割り振り、同時に何らかのリクエストされると、リクエストの内容は違うにも関わらず、同じ処理をしてしまい不整合が生じてしまいます。
ケース③:二重注文
リクエストが、ダブルクリックや完了画面をリロードしてしまうことで重複して繰り返されてしまうことです。一度処理したかのハンドリングを怠ってしまい、不整合が生じるケースです。
2.トランザクションとACIDの原則
トランザクションとは?
トランザクションとは、分けることのできない一連の処理の単位を指します。なお、実行中のトランザクションに他のトランザクションが割り込むと、予期せぬ結果を招いてしまいます。
トランザクションとACIDの原則
別のトランザクションが割り込み、不整合が生じることを防ぐために、ACIDの原則が設けられています。
Atomicity:
一連の処理結果が、全て成功したか全てなかったことになったのか明らかになる
Consistency:
システムに与えられた制約条件を破るトラクションは存在しない
Isolation:
トランザクションを実行する過程は他のトランザクションから独立していて見えない
Durability:
トランザクション完了をクライアントに通知したら、その結果は必ず永続化され残る
4つの原則のうち、トランザクションの独立性を担保させる「Isolation」の原則には特に注意しなけらばなりません。また、ACIDの原則を用いても用いらずとも、トランザクションを結合させないためには直列に実行すればよいのではないかと思いますが、それではシステムとしての性能が発揮しません。そのため、トランザクションを同時に実行しても正しい解釈が得られるように、制限を緩める必要があります。
正しい解釈
システムの動作において、正しい解釈は存在しません。開発者、ユーザーの思い通りにシステムが正常に動きさえすれば良いのです。ですがエラーが生じる要因、すなわち正しく無い解釈は明確は存在します。
Dirty Read
あるユーザーがトランザクション実行中に、他のユーザーが割り込んでしまい、処理が未確定のまま更新途中のデータを読み込んでしまうこと。
Lost Update
実行中のトランザクションに他のトランザクションが割り込むことで、更新されたデータを失ってしまうこと。
Inconsistent Read
実行中のトランザクションに他のトランザクションが割り込むことで、複数の情報を読み込む際に、別のユーザーの更新を反映してしまうこと。
代表的な正しくない解釈は以上になります。しかし、複雑な処理を行うソフトウェア開発において、これらすべての解釈を防ぐことは現実的には難しいため、解釈の正しさのレベルを設けると良いでしょう。例えば、あるシステム設計の際に、「Dirty Read」は許容するのなど、トランザクション毎にレベルの設定をするのです。
3.ロックによる排他制御の実行
排他制御の実行には、トランザクションの「ロック」が必要です。ロックとは共有リースに対し、複数のアクセスがなされる際に、トランザクションの割り込みができないようにすることです。更新時にロックをかけ、更新終了時に解除することで、トランザクションの独立性を担保することができます。
また、それだけでは万能ではないので、複数リソースに対してもロックを実行することも可能です。
ロック実行時にはデッドロックの発生にも気を付けましょう。ロックをかけることで、各ユーザーがリソースのロック解除を待ち続け、どちらも身動きが取れなくなってしまう状態がデッドロックです。このデッドロックを完全に防ぐことは難しいため、発生する可能性を低くする対策が現実的と言えるでしょう。具体的な対策としては、以下が挙げられます。
・トランザクションからアクセスするリソースの順番を一通り決める
・トランザクションを可能な限り短くする
・不要なロックを避ける
・ロックの粒度を最小限小さくする
・ロックモニターを機能させ、検出時にはタイムアウトされるように設定する
4.排他制御のパターン
最後に、開発現場で用いる排他制御のパターンを確認しましょう。
排他制御の方式は以下の2つになります。
楽観ロック
大抵のことでは他社との同時更新は起きないであろうという、楽観的な思考による制御。データに対してロックは行わずに、対象のデータがデータ取得時と同じ状態であることを確認してから更新することで、データの整合性を保証する方式。
悲観ロック
他者が同じデータに頻繁な変更を加えるであろう、という悲観的な思考による制御。更新対象となるデータにロックをかけることで、他のトランザクションから更新できないようし、データの整合性を保証する方式。
また、悲観ロックはユーザの利便性や業務効率性とのトレードオフになるため、ロックの仕様は「楽観」→「悲観」の順で検討します。一貫性の保証の必要ないところまでロックすると、性能や開発効率の低下を招くので、不要なロックを避け、最小限の工数・規模で着手するべきです。
終わりに
以上が今回のPETSのレポートでした。いかがでしたか?
こちらをご覧になられた方の力に少しでもなれましたら幸いです。
同時の情報処理におけるエラーケースを防止し、ユーザーと開発者の両サイドから見ても扱いやすいトランザクションやロックを設けることが最適な排他制御の実行に繋がるのです。
パクテラでは引き続き、日本のDX化を促進させる活動の一環として社内研修の内容をご報告させていただきます。是非、今後ともよろしくお願いいたします。
最後になりますが、ご一読いただきありがとうございました。
今までのPETSに関する投稿はこちらになります。ご興味のある方は、是非ご覧ください。
パクテラ・コンサルティング・ジャパン株式会社では一緒に働く仲間を募集しています