Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
多重登録を防御するためのノウハウ
Search
Ryohei KOMATSUYAMA
May 15, 2024
Programming
0
160
多重登録を防御するためのノウハウ
2024/05/15【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit
Ryohei KOMATSUYAMA
May 15, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
Webエンジニア主体のモバイルチームの 生産性を高く保つためにやったこと
igreenwood
0
330
42 best practices for Symfony, a decade later
tucksaun
1
180
KMP와 kotlinx.rpc로 서버와 클라이언트 동기화
kwakeuijin
0
130
Effective Signals in Angular 19+: Rules and Helpers @ngbe2024
manfredsteyer
PRO
0
130
たのしいparse.y
ydah
3
120
Scalaから始めるOpenFeature入門 / Scalaわいわい勉強会 #4
arthur1
1
300
MCP with Cloudflare Workers
yusukebe
2
220
LLM Supervised Fine-tuningの理論と実践
datanalyticslabo
3
920
プロダクトの品質に コミットする / Commit to Product Quality
pekepek
2
760
コンテナをたくさん詰め込んだシステムとランタイムの変化
makihiro
1
120
layerx_20241129.pdf
kyoheig3
2
290
テストコード文化を0から作り、変化し続けた組織
kazatohiei
2
1.5k
Featured
See All Featured
A better future with KSS
kneath
238
17k
Gamification - CAS2011
davidbonilla
80
5.1k
Building a Scalable Design System with Sketch
lauravandoore
460
33k
StorybookのUI Testing Handbookを読んだ
zakiyama
27
5.3k
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
251
21k
YesSQL, Process and Tooling at Scale
rocio
169
14k
Designing for humans not robots
tammielis
250
25k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
59k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.4k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.2k
Making the Leap to Tech Lead
cromwellryan
133
9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Transcript
多重登録を防御するためのノウハウ 2024/05/15 【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit 小松山凌平
👓 小松山 凌平 👶 1998/09/09 生 (2021 年卒) 🏢 開発
1 部 Cosmos 基盤グループ 🧻 BE メインのエンジニア 🏀 NBA 観戦 🧌 Monster Hunter World 🙅 x.com/kmtym_dev zenn.dev/kmtym1998 2 自己紹介
多重登録をデータベースレベルで防御できると安心です API 実装の際の手札を増やしてもらいたいです (PostgreSQL を前提とした話をします) 3 今日のメッセージ
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 4 話すこと
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 5 話すこと
• とあるシステムのユーザ管理機能を例にする • ユーザが持つ情報 ◦ ユーザID ◦ 名前 ◦ メールアドレス
◦ ステータス (招待済 / 登録済 / 削除済 の 3 値をとる) • ユーザに関する制約 ◦ "招待済" "登録済" のユーザはメールアドレスが重複しない 6 説明のための例 (要件)
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 値
8 • 招待者のダブルサブミットによって 招待済ユーザが 2 人できてしまった • 一応重複チェックはしていたつもり ◦ メールアドレスが一致
&& "削除済" でない ユーザがいるか検索 ◦ 検索して見つからなければ新規にレコード作成 • ダブルサブミットによってリクエストが 並列に処理され、ロジックをすり抜けた 多重登録によるトラブル エラーハンドリング等は省略しています
• 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ 9 話すこと
10 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
• トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける 11 多重登録を防ぐためのアプローチ
• 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦
リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 12 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
• 同時に複数のトランザクションが発生したときの挙動を決めるオプション • 標準 SQL で定められているものが以下の 4 つ (下に行くほど分離性が強い) ◦
リードアンコミッティド ◦ リードコミッティド (PostgreSQL のデフォルトはこれ) ◦ リピータブルリード (MySQL のデフォルトはこれ) ◦ シリアライザブル 13 トランザクション分離レベルとは・・・ PostgreSQLでの挙動
デフォルトの分離レベルがデータベース 単位で決まっている (変更可能) 14 トランザクション分離レベルの指定 トランザクション開始時に個別で設定も可能
シリアライザブル分離レベルは、最も厳しいトランザクションの分離性を提供します。このレベルでは トランザクションが同時にではなく、次から次へと、あたかも順に実行されているように逐次的な トランザクションの実行を全てのコミットされたトランザクションに対しエミュレートします。 PostgreSQL 15.4 文書 - 13.2 トランザクション分離 15
トランザクション分離レベル: シリアライザブル トランザクションの直列性を保証したいときに使う ※ ただし、相対的にパフォーマンスは悪くなる
16 TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ユーザ登録 コミット 並列検出🔎
TX開始 重複チェック ユーザ登録 コミット TX開始 重複チェック ロールバック 成功 ✅ 成功 ✅ 重複検出🔎 直列なトランザクション 並列なトランザクション
17 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
• 複数のトランザクションから同時に同じデータを 操作させないようにするための仕組み • トランザクション A がロックをかけているとき、 トランザクション B がロックをかけようとすると
A が解放されるまで B は待たされる • 重複チェックの前にロックをかける 18 テーブルロックとは・・・
19 別のトランザクションはロック解放を待つ TX開始 重複チェック ユーザの登録 コミット 成功 ✅ ロック 重複チェック
TX開始 ロック ロックの解放待ち 重複検出🔎 ※ 分離レベルはリードアンコミッティド・リードコミッティドを使う
20 • トランザクション分離レベルが高すぎると正しく重複チェックできない ◦ 並列して発生したトランザクションで作成されたレコードを読み取る必要がある ◦ リードアンコミッティド・リードコミッティドを使う • デッドロックに気を配る ◦
トランザクションが互いのロック解放を待つ状態となってしまい、いずれの処理も 止まってしまう状態 ◦ ロック時間の上限を設けておくなどして回避する • レコードロックでは重複登録は防げない 注意点
21 多重登録を防ぐためのアプローチ • トランザクション分離レベルを変更する • テーブルごとロックをかける • 部分インデックスを使ってユニーク制約をつける
22 部分インデックスとは・・・ 部分インデックスとは、テーブルの部分集合に構築されるインデックスです。 部分集合は、(部分イン デックスの述語と呼ばれる)条件式で定義されます。 部分インデックスには、その述語を満たすテーブ ル行のみに対するエントリが含まれます。 PostgreSQL 15.4 文書
- 11.8. 部分インデックス 普通のインデックス 部分インデックス ※ サポートがない RDBMS もある
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]
インデックスの範囲 インデックスの範囲 普通のインデックス 部分インデックス
インデックスの範囲 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]
インデックスの範囲 🙅 🙆 普通のインデックス 部分インデックス
25 部分インデックスのパフォーマンス (1)のグラフより、部分インデックスが定義されている条件であれば、通常のインデックスと部分イン デックスで実行速度に差がないことを確認できました。 (2)のグラフより、部分インデックスが定義されていない条件では、当然ですが通常のインデックスの 方が部分インデックスよりも高速に実行されます。 (※ B-Tree インデックスの場合) 株式会社インサイト
TECH BLOG - 部分インデックスの効果を検証(1)
26 話すこと • 多重登録によるトラブル • 多重登録を防ぐためのアプローチ • まとめ
• 忘れがちですが、多重登録はサーバ側で守れると安心です ◦ データベースレベルで防御できると堅牢になります • 重複チェックをするための方法を 3 つ紹介しました ◦ トランザクション分離レベルを上げる方法
◦ テーブルロックを使う方法 ◦ 部分インデックスを使う方法 • 同じような話を記事にしているので良ければご覧ください 27 まとめ
ありがとうございました