Upgrade to Pro — share decks privately, control downloads, hide ads and more …

多重登録を防御するためのノウハウ

 多重登録を防御するためのノウハウ

2024/05/15【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit

Ryohei KOMATSUYAMA

May 15, 2024
Tweet

Other Decks in Programming

Transcript

  1. 👓 小松山 凌平 👶 1998/09/09 生 (2021 年卒) 🏢 開発

    1 部 Cosmos 基盤グループ 🧻 BE メインのエンジニア 🏀 NBA 観戦 🧌 Monster Hunter World 🙅 x.com/kmtym_dev 󰩔 zenn.dev/kmtym1998 2 自己紹介
  2. • とあるシステムのユーザ管理機能を例にする • ユーザが持つ情報 ◦ ユーザID ◦ 名前 ◦ メールアドレス

    ◦ ステータス (招待済 / 登録済 / 削除済 の 3 値をとる) • ユーザに関する制約 ◦ "招待済" "登録済" のユーザはメールアドレスが重複しない 6 説明のための例 (要件)
  3. 7 説明のための例 (テーブル定義) カラム名 カラムの型 制約 id serial PRIMARY KEY,

    NOT NULL name text NOT NULL email text NOT NULL status enum NOT NULL • テーブル名: users • users.status の取り得る値は 'INVITED' / 'REGISTERED' / 'DELETED' の 3 値
  4. 8 • 招待者のダブルサブミットによって 招待済ユーザが 2 人できてしまった • 一応重複チェックはしていたつもり ◦ メールアドレスが一致

    && "削除済" でない ユーザがいるか検索 ◦ 検索して見つからなければ新規にレコード作成 • ダブルサブミットによってリクエストが 並列に処理され、ロジックをすり抜けた 多重登録によるトラブル エラーハンドリング等は省略しています
  5. • 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦

    リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 12 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
  6. • 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦

    リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 13 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
  7. 16 TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ユーザ登録 コミット 並列検出🔎

    TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ロールバック 成功 ✅ 成功 ✅ 重複検出🔎 直列なトランザクション 並列なトランザクション
  8. 19 別のトランザクションはロック解放を待つ TX開始 重複チェック ユーザの登録 コミット 成功 ✅ ロック 重複チェック

    TX開始 ロック ロックの解放待ち 重複検出🔎 ※ 分離レベルはリードアンコミッティド・リードコミッティドを使う
  9. 20 • トランザクション分離レベルが高すぎると正しく重複チェックできない ◦ 並列して発生したトランザクションで作成されたレコードを読み取る必要がある ◦ リードアンコミッティド・リードコミッティドを使う • デッドロックに気を配る ◦

    トランザクションが互いのロック解放を待つ状態となってしまい、いずれの処理も 止まってしまう状態 ◦ ロック時間の上限を設けておくなどして回避する • レコードロックでは重複登録は防げない 注意点
  10. 23 部分インデックスのあるテーブルへの INSERT id status email 1 REGISTERED [email protected] 2

    REGISTERED [email protected] 3 INVITED [email protected] 4 INVITED [email protected] 5 DELETED [email protected] id status email 1 REGISTERED [email protected] 2 REGISTERED [email protected] 3 INVITED [email protected] 4 INVITED [email protected] 5 DELETED [email protected] インデックスの範囲 インデックスの範囲 普通のインデックス 部分インデックス
  11. インデックスの範囲 24 部分インデックスのあるテーブルへの INSERT id status email 1 REGISTERED [email protected]

    2 REGISTERED [email protected] 3 INVITED [email protected] 4 INVITED [email protected] 5 DELETED [email protected] 6 INVITED [email protected] id status email 1 REGISTERED [email protected] 2 REGISTERED [email protected] 3 INVITED [email protected] 4 INVITED [email protected] 5 DELETED [email protected] 6 INVITED [email protected] インデックスの範囲 🙅 🙆 普通のインデックス 部分インデックス