builderscon2017/RDBアンチパターンリファクタリング
#builderscon2017
@soudai1025さん
akix.icon感想
今似たようなことをやっていてつらいところだったので聞けてよかった
キーワードがたくさん出てきたので、ひとつずつ詳しく調べたい感じ
知らないキーワードが結構あったので、勉強する部分が多いと思った
-.icon
https://speakerdeck.com/soudai/rdb-antipattern-refactoring
#MySQL
不適切なデータベースがサービスの成長を止める
データベースリファクタリング
この本がオススメだが、既に廃盤
原著は英語版
オンプレだろうとクラウドだろうと設計はずっと重要
自己紹介
はてな
Mackerel
$ curl -sIL mackerel.io | grep engineer
日本PostgreSQLユーザー会
RDBアンチパターン
SoftwareDesignで連載
データベースの不吉な臭い
「データは生き物」変化する成長する変わっていく
☞ 基本的に追加されていく
データベース設計は積み木
しっかり練られた初期設計☞ちゃんと設計された仕様追加☞という順番ならOK
初期設計がマジカルな設計だと仕様変更ができない
RDBアンチパターンを見極める
例:
SELECT delete_flag WHERE users;とかでなぜか1〜99/nullが入ってる
NOT NULLつけてバグ防げよ、とか
99はなぜか入る、みたいな
詳しくは連載で
RDBアンチパターンでググると全部soudaiさん
複数目的のカラム
会員は入会日、スタッフは入社日、とかだと怪しい
「RoRがわるい!」「WordPressがわるい!」
仕様変更にはまあ強い
冗長なデータ
非正規化の末に整合性がとれなくなる
外部キー制約を貼るとつらいことが起きる
JOINが気になる
☞ 非正規化しましょうとか言い出す
テーブルAとテーブルBでズレが起きてたりする
カラムが多すぎるテーブル
memo1, memo2, memo3...とか
本当に必要な場合は複数のエンティティを1つにしている場合がある
行が多すぎるテーブル
不要なデータは削除しましょう
論理削除やめよう
本当に必要ならパーテーションやシャーディング
「スマート」カラム
論理IDなどデータ中の情報で意味が変わっちゃうやつ
ユーザーIDの先頭でスタッフかどうか判別してる、とか
変更の恐怖
アプリが壊れる恐怖と向き合うようでは既にアンチパターン
データベースの不吉な臭い☞技術的負債
チーズか腐った牛乳か?
チーズならビジネス的な価値を生んでいるので残しておいていい
腐った牛乳はお腹を壊すので治しましょう
☞本当に改修が必要か、の判断になる
データベース・リファクタリング
なにをリファクタリングするか
構造リファクタリング
テーブルやViewの定義
データ品質リファクタリング
データの値
参照整合性リファクタリング
テーブルの関連性
アーキテクチャ・リファクタリング
アプリとのインタフェース
変更リファクタリング
テーブルやカラムの追加
メソッド・リファクタリング
ストアドプロシジャ
なにをリファクタリングするか?
☞システムの性質によっても変わる
シングルアプリケーション
1つのアプリが1つのDBを扱う
DBマイグレーションが活きる
RoRの最大の功績はActiveRecordがよくできてる
コードでDBを管理できる強さがある
gitのログで分かるコミュニケーションとれるレビューできる
マルチアプリケーション
サービスの成長、複数サービス
アプリ/バッチ処理が複数で1〜nのデータベースを参照してる
SaaSとかSendGridとかを使ってる、とかのAPIフックも関係してくるよね
DBマイグレーションがそのまま使えない場合がある
同じようなツールを使い回せない
Aサーバーは24時間営業だから止められない、とか
依存関係の多いマルチアプリケーションDBをリファクタリングする
プロセスとリファクタリング戦略
DBは生き物
常にデータが変化してる
影響範囲が広い
DBを止めることが難しい
DB止めるとシステム止まっちゃうし
DBリファクタリングはすごく長いスパンになる
1,2ヶ月かかるとか全然ある
アプリの性質によっては1,2年かかったりする
戦うための準備をする
1. 抽象化
DBの接続を抽象化する永続化フレームワーク or OR wrapper or micro serviceとかとか
アプリケーション側から変更しやすくする
RESTfulAPIとかWebHookだと抽象化されてなかったりする
2. モニタリング
テストコードではパフォーマンスが落ちたか上がったか分からない!
サービスが止まったとかだけじゃなくて、パフォーマンスも見る
負荷テストは人間が想定しているものしか書けない
なのでモニタリングが大事
3. 品質を担保する
テストコードはコードの品質の見える化 @t_wada
シナリオテストとかも書くべき
WebだとSeleniumとかPhantomJSとか
ユニットテストに近い形でもやっとくべき
アプリAはテストあるけどアプリBがテストほとんどないとかはダメ
ちゃんとアプリのテストは全部のサービスで書きましょう
4. 覚悟
サービスの停止の壁
どんなDB使おうが、ゼロにはできない
限りなく短くするのはできる
レプリケーションとかクラウドとか
政治と技術の両方で解決する
影響範囲が分からない
☞ テストコードとモニタリングでカバーする
自分を守ってくれる部分でもある
無停止の仕組みを作るのは難しい
エンドユーザーや上長に理解を求める
これだけ揃えて行うだけの価値があるかどうか?
「大変だけど来月このサービス終わるわ〜」とかならコスト避けない
「夏限定サービス!」とかなら要らないよね
「命運を担ってる」とかなら投資価値あるよね
手間も時間もかかるからこそ、リファクタリングする価値があるか検討が大事
リファクタリングの意味はあるか?
かっこわるいから直そうぜがコストに見合うかどうか
作業に応じた効果はあるか?
パフォーマンスが上がるか?
改修側がどれだけ楽になるか?
何が嬉しいか?
今やるべきか?
売り上げ最優先だっけ?とか
いつやるか、とか
すべてのアプリケーションが正しく動く必要がある
同時に変更できない場合は移行期間が必要
AからもBからも動くとかなら
モニタリングにはMackerelがいいよ!
例えば年齢カラムからいきなり生年月日カラムだけにすると事故る
移行期間を握った上で設定して、年齢カラムを消す
コメントのところに「4月1日に消します」って入れておく
トリガー機能
新アプリINSERT時に年齢が無いが生年月日からトリガーで年齢を計算する
トリガーと年齢テーブルを消す、とかやると移行しやすい
小さな変更を長いスパンで繰り返す
DBは影響範囲が広いので切り分けをしやすくする
テストとモニタリング
品質が分かるので超大事
体重計なしのダイエットみたいなことになっちゃうよ
現場で戦うあなたへ
参照と更新の読み込み先を分ける
更新のボトルネックを分ける
データ設計を見直す
適切にINDEXを活用する
闇が深いリファクタリング
非正規化しちゃえ
ロックが怖いから外部キーはずそう
パフォーマンス出ないからキャッシュに突っ込む
極度のスケールアップ
金かねの弾丸
DBの機能を上手く使う
PostgreSQLならトリガーとか
MySQLなら仮想列とか
トリガーみたいなことを勝手にやってカラムを作ってくれる
マテリアライズドビュー
OSSのコミュニティをうまく活用する
postgreswql-jp slack
mysql-casual slack
まとめ
データベースの寿命はアプリケーションより長い
一度作ったDBは消せない!
しんどい設計でもDBごとは消せない
問題は小さいうちに直す
DB肥大化と共に問題も大きくなる
DBの問題は忘れた頃にやってくる
「DBの問題解決出来る人は単価が高い」
サービスの死は機会損失の死
DBが大きくなってるということはビジネスが大きくなってる
お金持ってる人の問題を解決できるよ!
愚者は経験に学び、賢者は過去に学ぶ
周囲の経験談から学ぶ
本を読む
さっき紹介したSlackは優しい世界
RDBの知識は寿命が長い
質疑応答
MongoDBとPostgresqlを併用している、mongoをやめたい
postgreqlにはJSON型がある
FDW外部データラッパー
Postgresqlのように他のDBを見ることができる
参照系だけポスグレに持って行くみたいなことができる
この指標が変化するので注視した方がいいという数値はあるか?
マカレルのDB用プラグインがある
はてなの見てる指標がマカレルのプラグインに反映されている
パフォーマンススキーマの情報が出るようになったよね、とか色んな背景がある
マルチアプリケーションのテストコードをアプリ経由せずテストできるのか?
ユニットテスト・シナリオテストはアプリ参照
3種類ぐらいある
ストアドテスト
DBの機能をチェックする
データの中身
都道府県47個あるはずなのに48個ある、とかだとおかしい
会員数が減ってないとか
課金ロジックの変更が無い検査とか
パフォーマンスのテスト
モニタリングもそうだけど
SELECT/COUNTとか
投入前のデータを検査するということ?
ユーザーテーブルを移行させるのに切り替える時とかにカウントが変わりやすかったりするので、変更前変更後の値をチェックするとかそういう感じ
データセットの整合性を見る