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
220
多重登録を防御するためのノウハウ
2024/05/15【DMM×バイセル】若手エンジニアによる学生向けTech Study Summit
Ryohei KOMATSUYAMA
May 15, 2024
Tweet
Share
Other Decks in Programming
See All in Programming
Things You Thought You Didn’t Need To Care About That Have a Big Impact On Your Job
hollycummins
0
230
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
170
大規模アプリのDIフレームワーク刷新戦略 ~過去最大規模の並行開発を止めずにアプリ全体に導入するまで~
mot_techtalk
1
450
アメ車でサンノゼを走ってきたよ!
s_shimotori
0
230
CSC305 Lecture 04
javiergs
PRO
0
270
kiroとCodexで最高のSpec駆動開発を!!数時間で web3ネイティブなミニゲームを作ってみたよ!
mashharuki
0
570
10年もののAPIサーバーにおけるCI/CDの改善の奮闘
mbook
0
830
株式会社 Sun terras カンパニーデック
sunterras
0
320
『毎日の移動』を支えるGoバックエンド内製開発
yutautsugi
2
250
All About Angular's New Signal Forms
manfredsteyer
PRO
0
170
overlayPreferenceValue で実現する ピュア SwiftUI な AdMob ネイティブ広告
uhucream
0
180
その面倒な作業、「Dart」にやらせませんか? Flutter開発者のための業務効率化
yordgenome03
1
130
Featured
See All Featured
Being A Developer After 40
akosma
91
590k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
8
910
Embracing the Ebb and Flow
colly
88
4.9k
The Cult of Friendly URLs
andyhume
79
6.6k
Optimizing for Happiness
mojombo
379
70k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
Become a Pro
speakerdeck
PRO
29
5.6k
Scaling GitHub
holman
463
140k
Building Better People: How to give real-time feedback that sticks.
wjessup
369
20k
Docker and Python
trallard
46
3.6k
Context Engineering - Making Every Token Count
addyosmani
6
260
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 まとめ
ありがとうございました