排他制御とは?複数処理の同時アクセスによるデータ壊れを防ぐ仕組み

システム開発・テクノロジー
排他制御とは?ざっくりと3行で
  • 複数のプロセスやスレッドが同じデータや資源に同時にアクセスすることを防ぎ、一度に1つの処理だけがアクセスできるよう制限する制御の仕組みのこと
  • 排他制御がないと複数の処理が同じデータを同時に読み取り・更新することでデータの整合性が崩れる「競合状態(レースコンディション)」が発生し、重大なバグや不正な状態を引き起こす
  • ミューテックス(Mutex)・セマフォ・データベースのロック(行ロック・テーブルロック)・楽観的ロック・悲観的ロックなど実装手段が多様で、用途と性能要件に応じて使い分けることが重要だ

【深掘り】これだけ知ってればOK!

排他制御が必要な場面を銀行口座の例で理解しよう。残高1万円の口座に2つのATM(処理A・処理B)が同時にアクセスし、両方が「現在の残高:1万円」を読み取った後、それぞれが5千円を引き落とす処理を実行したとする。排他制御なしでは両方の処理が「1万円-5千円=5千円」という結果をDBに書き込み、合計1万円の引き落としが発生したのに残高が5千円になってしまう「データの消失」が起きる。

排他制御の主な実装方法を整理しよう。ミューテックス(Mutex:Mutual Exclusion):1つのスレッドしかロックを取得できない最もシンプルな排他制御。プログラミング言語レベルで実装される。セマフォ:同時にN個のスレッドまでアクセスを許可する制御。接続プールの管理などに使われる。データベースの悲観的ロック:データを読み取る時点でロックをかけ、他の処理が変更できないようにする(SELECT FOR UPDATE)。楽観的ロック:バージョン番号や更新日時を使って更新時に競合を検出する手法。ロックなしで高いスループットを実現できる。

楽観的ロックと悲観的ロックの使い分けを理解しよう。悲観的ロックは読み取り時にロックをかけるため競合を確実に防げるが、ロック待ちによるパフォーマンス低下・デッドロックのリスクがある。楽観的ロックは更新時に「この間に別の処理が更新していないか」をバージョン番号で確認する。競合が少ない場合はパフォーマンスが高いが、競合が多い場合はリトライコストが増大する。

デッドロックは排他制御の実装で最も注意が必要な問題だ。デッドロックとは、処理Aがリソース1をロックした後リソース2を待ち、処理Bがリソース2をロックした後リソース1を待つという「相互に待ち合う状態」で処理が止まる現象だ。防ぐためには「常に同じ順序でロックを取得する」「ロックの保持時間を短くする」「タイムアウト付きのロック取得」という3つの原則を守ることが重要だ。

Webアプリケーション開発での排他制御の実践として、在庫管理・予約システム・ポイント残高更新など「二重処理を許してはいけない」業務処理にはデータベースのトランザクションと悲観的ロック(SELECT FOR UPDATE)を使うことが一般的だ。またRedisのSETNX(Set if Not eXists)を使った分散ロックは、複数サーバー間の排他制御に使われる。

よくある誤解

排他制御はシングルスレッドのプログラムには不要だと思っている

シングルスレッドのプログラムでも、複数のプロセスが同じデータベースやファイルにアクセスする場合は排他制御が必要だ。Webアプリケーションはリクエストごとにスレッドやプロセスが並行して動くため、シングルスレッドのコードでも共有データへの排他制御が必要になる。

ロックをかければ全ての並行処理の問題は解決すると思っている

ロックを多用するとデッドロック・ロック待ちによるパフォーマンス低下・スループット低下という新たな問題が生じる。排他制御の設計はロックの粒度(行ロック vs テーブルロック)・ロックの保持時間・楽観的ロックとのバランスを考慮した設計が重要だ。

会話での使われ方

ITKAGYO運営者デプロイ太郎のアイコン画像

在庫の更新処理、SELECT FOR UPDATEで行ロックをかけてからデクリメントしてください。排他制御なしだと在庫のマイナス販売が起きます。

バックエンドエンジニアがECサイトの在庫管理で排他制御の実装方法を後輩に指示している場面。

ITKAGYO運営者デプロイ太郎のアイコン画像

デッドロックが発生しています。処理Aと処理Bがテーブルのロックを逆順に取得しているのが原因です。常に同じ順序でロックを取得するよう修正してください。

シニアエンジニアがデッドロックの原因を特定して修正方針を指示している場面。

ITKAGYO運営者デプロイ太郎のアイコン画像

フラッシュセールで同一商品への同時アクセスが多いので、悲観的ロックだとボトルネックになります。楽観的ロックとバージョン管理で競合検出して在庫管理する設計にしましょう。

アーキテクトが高トラフィック環境でのパフォーマンスと整合性のバランスを考慮した設計を提案している場面。

【まとめ】3つのポイント

  • 一度に1つの処理だけがデータにアクセスできるよう制限する制御:複数の処理が同じデータに同時アクセスすることで起きる競合状態(レースコンディション)を防ぎ、データの整合性を保証するために必須の制御技術だ
  • 悲観的ロックは確実性・楽観的ロックはパフォーマンス優先で使い分ける:競合が多い・重要度が高いデータには悲観的ロックを使い、競合が少ない・スループット重視のデータには楽観的ロックを使うという使い分けが実務的なアプローチだ
  • デッドロックは常に同じ順序でロックを取得して防ぐ:複数のリソースをロックする際は常に決まった順序で取得することとロックの保持時間を短くすることが、デッドロックを防ぐ最も基本的な設計原則だ

よくある質問

Q
ミューテックスとセマフォの違いは何ですか?
A

ミューテックスは「1つのスレッドのみがロックを取得できる」排他制御です。セマフォは「同時にN個のスレッドまでアクセスできる」カウンタ型の制御で、接続プールの管理(最大10接続まで許可など)に使われます。ミューテックスはセマフォのカウント値が1の特別なケースと言えます。

Q
楽観的ロックはどのように実装しますか?
A

テーブルにversionカラムを追加して、UPDATE時に「WHERE id=? AND version=?」という条件で更新します。更新件数が0だった場合(別の処理が先に更新した)は競合と判断してリトライします。ORMフレームワーク(Hibernate・Sequelizeなど)は楽観的ロックを自動的にサポートしているものも多いです。

Q
排他制御はITパスポートの試験に出ますか?
A

基本情報技術者試験・応用情報技術者試験では排他制御・デッドロック・セマフォが頻出テーマです。ITパスポートでも「データの整合性を保つための仕組み」として出題されることがあります。「複数の処理が同じデータを同時更新するとどうなるか」というシナリオ問題が典型的です。

Q
Redisを使った分散ロックとは何ですか?
A

複数のサーバーインスタンス間で排他制御を実現するための仕組みです。RedisのSETNX(Set if Not eXists)コマンドを使って、鍵が存在しない場合のみセットするという操作でロックを実装します。RedLockというアルゴリズムで複数のRedisノードに対してロックを取得することで信頼性を高めることができます。

この用語と一緒に知っておきたい用語

用語 この記事との関連
データ 本記事のテーマと実務上セットで使われることが多い用語です。コンピュータが処理する数値や文字、画像といった事実や資料そのもの、それがデータだ
セマフォ 次のステップとしてセマフォを学ぶと知識が広がります。複数のプロセスやスレッドが共有リソースに同時アクセスして壊れる問題を防ぐための同期制御機構のこと。整数カウンターで同時アクセス可能数を管理する
リソース リソースとの関係を知ると全体像がつかみやすくなります。コンピューターを動かすための性能や、プロジェクトを進めるための人員・時間といった資源のこと!
データベース データベースは関連分野でよく登場する重要キーワードです。データを効率よく蓄積・検索・更新・削除できるよう構造化して管理する仕組みの総称。専用エンジンを持ち大量データを高速操作できる
スループット スループットを押さえると本記事の理解がさらに深まります。単位時間あたりに、どれだけのデータを処理・転送できるかという「実質の作業スピード」のことだよ!

【出典】参考URL

https://www.postgresql.org/docs/current/explicit-locking.html :PostgreSQL公式「明示的ロック」のドキュメント
https://dev.mysql.com/doc/refman/8.0/ja/innodb-locking.html :MySQL InnoDBのロックの仕組み
https://redis.io/docs/manual/patterns/distributed-locks/ :RedisによるRedLockの説明

コメント

「IT用語、難しすぎて心が折れそう……」という方のための、ハードル低めな用語辞典です。

情報レベルは「基礎中の基礎」。会話を止めないためのエッセンスだけを抽出しています。分かりやすさを追求するあまり、時々例え話が暴走しているかもしれませんが、そこは「ほどよく」聞き流していただけると幸いです。
ほどよくIT用語辞典システム開発・テクノロジー
デプロイ太郎のSNSを見てみる!!