MyFleetGirlsがSQLのミスで死んだ
はじめに
MyFleetGirlsにDBのTableが増えるような新機能を入れたら、SQLにwhere句を1つ付け忘れただけで、1時間でDBを埋め尽くし、load averageを通常時の10倍以上に増やした事件の話。
新機能
新機能とはシンプルなもので、艦娘の経験値グラフを追加するものである。現行では艦娘の最新情報のみ保持しているので、履歴を別途取っておく必要がある。これが新しいTableに保存される。
このTableは簡単にRecord数の爆発が予想される。従って、最終更新からの差分を計算し、必要であればinsertするような仕組みを考えた。この部分にSQLのミスを埋め込んだ。
問題のTableはship_historyで、以下のようなものである。
バグの内容
バグの修正commitは以下。
https://github.com/ponkotuy/MyFleetGirls/commit/26d741efb21c2879856c33b8cf797995718627fb
member_idの条件を入れ忘れている。findAllLastest関数はこんな感じ
findAllLastestではwhere条件における最後に生成されたship_historyを返す。このときwhere条件としてcreatedを指定している。追加で引数のwhere条件を付け足している。
member_idの条件を入れ忘れた結果、2つの事象が発生する
- 全く関係ないデータがヒットすることで常に差分が大きくなるので、全くfilterできてない
- UNIQUE KEYの先頭のmember_idがwhere条件に入らないことで、Indexが効かなくなる
こうしてTableは肥大化し、非効率的なクエリによって、1時間でサーバリソースを食い尽くすまでに至る、というわけである。