Slide 1

Slide 1 text

RDBのトラブルの現場を追え!
 ~ 様々な現場を見る ~
 builderscon tokyo 2019

Slide 2

Slide 2 text

What is it?
 RDBMSの死はサービスの死


Slide 3

Slide 3 text

What is it?
 ● DBが突然遅くなった…
 ● コネクションが溢れてサービス停止…
 ● INDEXを貼ろうとしたらエラー…
 現場の声


Slide 4

Slide 4 text

What is it?
 現場の 悲鳴 声のお届けします


Slide 5

Slide 5 text

あじぇんだ
 1. 自己紹介
 2. 初級編:スロークエリを追え!
 3. 中級編:エラーログを追え!
 4. 上級編:未知のエラーを追え!
 5. 番外編:何もしてないのにDBが壊れた
 6. まとめ


Slide 6

Slide 6 text

あじぇんだ
 1. 自己紹介
 2. 初級編:スロークエリを追え!
 3. 中級編:エラーログを追え!
 4. 上級編:未知のエラーを追え!
 5. 番外編:何もしてないのにDBが壊れた
 6. まとめ


Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

この話はこっちのスライドを見てください
 https://speakerdeck.com/soudai/rdb-troubleshooting

Slide 9

Slide 9 text

あじぇんだ
 1. 自己紹介
 2. demo 1
 3. demo 2
 4. demo 3
 5. demo 4
 6. まとめ


Slide 10

Slide 10 text

あじぇんだ
 1. 自己紹介
 2. demo 1
 3. demo 2
 4. demo 3
 5. demo 4
 6. まとめ


Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 14

Slide 14 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 15

Slide 15 text

自己紹介
 曽根 壮大(34歳)
 株式会社 オミカレ 副社長 CTO
 
 そ  ね   たけ とも
 ● 日本PostgreSQLユーザ会 勉強会分科会 担当
 ● 3人の子供がいます(長女、次女、長男)
 ● 技術的にはWeb/LL言語/RDBMSが好きです
 ● コミュニティが好き

Slide 16

Slide 16 text

婚活といえばオミカレ
 https://party-calendar.net/

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

本書きました


Slide 19

Slide 19 text

先週のそーだいさん


Slide 20

Slide 20 text

昨日のそーだいさん


Slide 21

Slide 21 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 22

Slide 22 text

スロークエリの現場
 サービスを殺すには刃物は要らぬ。
 スロークエリがあれば良い。


Slide 23

Slide 23 text

スロークエリの現場
 
 REPLACE INTO hoge(id, name) SELECT id, name FROM foo AS f INNER JOIN bar AS b ON f.event_id = b.id WHERE f.id in ( SELECT max(event_id) FROM f WHERE canceled_at IS NULL GROP BY event_id, sheet_id );

Slide 24

Slide 24 text

スロークエリの現場
 もうおわかりですね?


Slide 25

Slide 25 text

スロークエリの現場
 
 REPLACE INTO hoge(id, name) SELECT id, name FROM foo AS f INNER JOIN bar AS b ON f.event_id = b.id WHERE f.id in ( SELECT max(event_id) FROM f WHERE canceled_at IS NULL GROP BY event_id, sheet_id );

Slide 26

Slide 26 text

スロークエリの現場
 
 REPLACE INTO hoge(id, name) SELECT id, name FROM foo AS f INNER JOIN bar AS b ON f.event_id = b.id WHERE f.id in ( SELECT max(event_id) FROM f WHERE canceled_at IS NULL GROP BY event_id, sheet_id ); REPLACE 構文はMySQLの独自構文


Slide 27

Slide 27 text

スロークエリの現場
 
 REPLACE INTO hoge(id, name) SELECT id, name FROM foo AS f INNER JOIN bar AS b ON f.event_id = b.id WHERE f.id in ( SELECT max(event_id) FROM f WHERE canceled_at IS NULL GROP BY event_id, sheet_id ); 一般的なサブクエリ


Slide 28

Slide 28 text

スロークエリの現場
 つまり…


Slide 29

Slide 29 text

スロークエリの現場
 MySQL 5.5 相当以下だと死ぬ


Slide 30

Slide 30 text

スロークエリの現場
 簡単でしたね


Slide 31

Slide 31 text

スロークエリの現場
 
 UPDATE hoge SET binary = ‘とてもでかい文字列’ WHERE id = 1;

Slide 32

Slide 32 text

スロークエリの現場
 バイナリをDBに保存するな?
 


Slide 33

Slide 33 text

スロークエリの現場
 バイナリをDBに保存するな?
 ↓
 それはそう


Slide 34

Slide 34 text

スロークエリの現場
 これがPostgreSQLだったら?


Slide 35

Slide 35 text

スロークエリの現場
 これがPostgreSQLだったら?
 ↓
 更新はコスト


Slide 36

Slide 36 text

スロークエリの現場
 HOT(Heap Only Tuples)があるでしょ?


Slide 37

Slide 37 text

スロークエリの現場
 HOT(Heap Only Tuples)があるでしょ?
 ↓
 更新後のデータが同じファイルでは無い時はHOTは 利用できません!!!


Slide 38

Slide 38 text

スロークエリの現場
 まぁPostgreSQLなのだから
 必要ならラージオブジェクトを使いましょう


Slide 39

Slide 39 text

スロークエリの現場
 まぁでかいデータをRDBMSに入れるな
 パスで良い
 (ファントムファイル?誤差です)


Slide 40

Slide 40 text

スロークエリの現場
 バルクインサート使ってます?


Slide 41

Slide 41 text

スロークエリの現場
 バルクインサート使ってます?
 ↓
 もっと早いのあります


Slide 42

Slide 42 text

スロークエリの現場
 MySQLならLOAD
 PostgreSQLならCOPY
 マジ便利なのでこれだけは覚えて


Slide 43

Slide 43 text

スロークエリの現場
 スロークエリは本当に様々ある


Slide 44

Slide 44 text

スロークエリの現場
 スロークエリは本当に様々ある
 ↓
 無知の豪腕と
 そもそもテーブル設計が悪いパターンがある


Slide 45

Slide 45 text

スロークエリの現場
 どちらに問題があるかを考えて
 適切に対応していくことが大事


Slide 46

Slide 46 text

スロークエリの現場
 スロークエリログを見て
 実行計画を見て
 TABLE設計を見直せば
 自然と道が見えてくるのじゃ


Slide 47

Slide 47 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 48

Slide 48 text

不正データの現場
 データは制約で守りましょう


Slide 49

Slide 49 text

不正データの現場
 完


Slide 50

Slide 50 text

不正データの現場
 …しかし制約でも守れないデータが!


Slide 51

Slide 51 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 1 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 4 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙

Slide 52

Slide 52 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 1 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 4 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙ 予約日時は必ず今よりも後


Slide 53

Slide 53 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 1 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 4 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙ キャンセル日時は必ず予約日時よりも後


Slide 54

Slide 54 text

不正データの現場
 素直にcheck制約で設定すると
 reservation_at > now()
 cancel_at > reservation_at


Slide 55

Slide 55 text

不正データの現場
 これで安心!とはならない…


Slide 56

Slide 56 text

不正データの現場
 過去のデータ、リストア出来ません!!!
 (テストでも困るし、リストアで困る)


Slide 57

Slide 57 text

不正データの現場
 なので最初に遅延制約をつけましょう
 (DEFERRABLE INITIALLY DEFERRED)
 ※PostgreSQLの場合


Slide 58

Slide 58 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 2 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 1 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙

Slide 59

Slide 59 text

不正データの現場
 キャンセルされて無いのに
 同じ席を予約されてはいけない


Slide 60

Slide 60 text

不正データの現場
 cancel_atが無い時は
 event_it+seat_idは組み合せユニーク
 


Slide 61

Slide 61 text

不正データの現場
 それPostgreSQLなら出来るよ
 (UNIQUE制約にWHERE句を付けれる)


Slide 62

Slide 62 text

スロークエリの現場
 
 CREATE UNIQUE INDEX event_seat_idx ON reservation (event_id,seat_id) WHERE cancel_at IS NULL;

Slide 63

Slide 63 text

不正データの現場
 完


Slide 64

Slide 64 text

不正データの現場
 とはならない!


Slide 65

Slide 65 text

不正データの現場
 レコードの連続性の正当性


Slide 66

Slide 66 text

不正データの現場
 そもそも


Slide 67

Slide 67 text

不正データの現場
 キャンセルされて無いのに
 同じ席を予約されてはいけない


Slide 68

Slide 68 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 2 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 1 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙

Slide 69

Slide 69 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 2 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 1 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙ キャンセルされてから、次のデータが正しい


Slide 70

Slide 70 text

不正データの現場
 id user_id event_id seat_id reservation_at cancel_at 1 1 2 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 1 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙ キャンセルされてなかったのに次のレコードが入ってる


Slide 71

Slide 71 text

不正データの現場
 実際の運用上、起こり得ないですよね


Slide 72

Slide 72 text

不正データの現場
 これの制約を書くのは大変なので割愛します


Slide 73

Slide 73 text

不正データの現場
 そもそもこんなデータ入らないでしょ?


Slide 74

Slide 74 text

不正データの現場
 テストデータとかバグとか
 ヒューマンエラーとかで入るんですよね


Slide 75

Slide 75 text

不正データの現場
 データはINSERTやUPDATEに成功しても
 それが正しいのは判断は難しい


Slide 76

Slide 76 text

不正データの現場
 制約でデータを守る
 テストで振る舞いを守る
 モニタリングでサービスを守る


Slide 77

Slide 77 text

不正データの現場
 適切な制約に
 適切なデータは宿る


Slide 78

Slide 78 text

不正データの現場
 正しさを常に求めていきましょう


Slide 79

Slide 79 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 80

Slide 80 text

パフォーマンスチューニングの現場
 そもそもさっきのreservationテーブル
 ロックが激しくて現実では厳しい
 (主にISUCON8)


Slide 81

Slide 81 text

パフォーマンスチューニングの現場
 seatテーブルには席の一覧がある


Slide 82

Slide 82 text

パフォーマンスチューニングの現場
 
 SELECT * FROM seat ORDER BY RAND() LIMIT 1;

Slide 83

Slide 83 text

パフォーマンスチューニングの現場
 空席考慮してないでしょ!
 (考慮したSQL、途端に長くなるので割愛)


Slide 84

Slide 84 text

再掲
 id user_id event_id seat_id reservation_at cancel_at 1 1 1 1 2019/08/19 09:10 null 2 1 2 1 2019/08/20 09:10 2019/08/21 09:10 3 1 2 4 2019/08/22 09:10 null 4 1 3 3 2019/08/23 09:10 null ︙ ︙ ︙ ︙ ︙ ︙

Slide 85

Slide 85 text

パフォーマンスチューニングの現場
 飲み友達に聞きました


Slide 86

Slide 86 text

パフォーマンスチューニングの現場
 InnoDBを使いこなす
 ならこうやで!
 (プライバシー保護のため加工されています)


Slide 87

Slide 87 text

remainsテーブルの例
 id event_id seat_id reservation_at 1 1 11049 null 2 1 5467 null 3 1 3333 null 4 1 14 null ︙ ︙ ︙ ︙

Slide 88

Slide 88 text

remainsテーブルの例
 id event_id seat_id reservation_at 1 1 11049 null 2 1 5467 null 3 1 3333 null 4 1 14 null ︙ ︙ ︙ ︙ InnoDBはクラスタインデックスなので
 event_idのINDEXを利用した時
 暗黙的にPKでソートされえる


Slide 89

Slide 89 text

remainsテーブルの例
 id event_id seat_id reservation_at 1 1 11049 null 2 1 5467 null 3 1 3333 null 4 1 14 null ︙ ︙ ︙ ︙ つまり先頭からとってランダム!


Slide 90

Slide 90 text

パフォーマンスチューニングの現場
 
 mysql> SELECT * FROM remains WHERE event_id = 1; +----+----------+---------+-------------+ | id | event_id | seat_id | reserved_at | +----+----------+---------+-------------+ | 1 | 1 | 29 | NULL | | 2 | 1 | 59 | NULL | | 3 | 1 | 10029 | NULL | | 4 | 1 | 2009 | NULL | | 5 | 1 | 2345 | NULL | | 6 | 1 | 8756 | NULL | +----+----------+---------+-------------+ 6 rows in set (0.00 sec)

Slide 91

Slide 91 text

パフォーマンスチューニングの現場
 https://soudai.hatenablog.com/entry/2018/05/01/204442

Slide 92

Slide 92 text

パフォーマンスチューニングの現場
 集合論から外れず
 しかしRDBMSの特性を活かした設計をする


Slide 93

Slide 93 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 94

Slide 94 text

突然DBが壊れた現場
 稀によくある


Slide 95

Slide 95 text

突然DBが壊れた現場
 まず壊れた種類を考える


Slide 96

Slide 96 text

壊れたとは何が?
 1. 突然パフォーマンスが悪化した
 2. データの不整合が発生している
 3. データベースが応答を返さない
 4. コネクションが溢れている
 5. 間違えてDROP TABLEしちゃった(バルス)
 ...etc


Slide 97

Slide 97 text

突然DBが壊れた現場
 壊れたを知るために
 モニタリングが大事s


Slide 98

Slide 98 text

突然DBが壊れた現場


Slide 99

Slide 99 text

突然DBが壊れた現場
 データベースは突然遅くなる


Slide 100

Slide 100 text

データベースは突然遅くなる
 1. データが増えて、tmp落ち
 2. CPUがサチってDisk ioに余力がない
 3. データ傾向が変わって実行計画が変わった
 4. そもそも意図した実行計画を使ってくれない
 5. 1つの小さな遅延がロックによって顕在化
 ...etc


Slide 101

Slide 101 text

突然DBが壊れた現場
 データはカジュアルに壊れる


Slide 102

Slide 102 text

データはカジュアルに壊れる
 1. バグやヒューマンエラーでデータは壊れる
 2. 予想外のデータはいつでも入る
 3. データファイルがDisk障害で死ぬことも
 4. レプリケーションでも場合によっては壊れる
 5. そもそもDROPの前では無力
 ...etc


Slide 103

Slide 103 text

突然DBが壊れた現場
 ヒューマンエラーやバグからは
 制約で守る


Slide 104

Slide 104 text

突然DBが壊れた現場
 バックアップとログは大事


Slide 105

Slide 105 text

突然DBが壊れた現場


Slide 106

Slide 106 text

突然DBが壊れた現場
 
 ???「エラーログで調べると
 自分のblogしか出てこないんですけど」
 


Slide 107

Slide 107 text

突然DBが壊れた現場
 
 ???「わかるぅ〜〜〜」
 (CV:そーだい)


Slide 108

Slide 108 text

突然DBが壊れた現場
 未知の問題を解決することが
 エンジニアの腕の見せ所


Slide 109

Slide 109 text

突然DBが壊れた現場
 
 ???「わかるぅ〜〜〜」
 (CV:そーだい)


Slide 110

Slide 110 text

突然DBが壊れた現場
 日本語コミュニティのSlackを活用する
 ↓
 mysql-casualとpostgresql-jp


Slide 111

Slide 111 text

あじぇんだ
 1. 自己紹介
 2. スロークエリの現場
 3. 不正データの現場
 4. パフォーマンスチューニングの現場
 5. 突然DBが壊れた現場
 6. まとめ


Slide 112

Slide 112 text

まとめ
 今日、学びはありましたか?


Slide 113

Slide 113 text

まとめ
 今日、学びはありましたか?
 ↓
 DBAの仕事のほんの一部です


Slide 114

Slide 114 text

まとめ
 でもそのDBAの仕事を
 みんなが出来るようにするのが
 DBREの仕事です


Slide 115

Slide 115 text

まとめ
 仕組みで課題を解決する


Slide 116

Slide 116 text

まとめ
 技術で課題を解決する


Slide 117

Slide 117 text

まとめ
 理想への一歩目を踏み出すのは
 自分自身


Slide 118

Slide 118 text

まとめ
 ご清聴ありがとうございました