ボクココ

サービス開発を成功させるまでの歩み

Heroku Addon 「Scout」 の紹介

ども、@kimihom です。

Heroku Addon の1つである Scout はRuby on Rails 専用のメトリクスサービスだ。一般的にこの類の Addon だと NewRelic が一般的だけども、重いしメモリも食うので Scout を使っている。今回はそんな Scout について簡単にご紹介しようと思う。

f:id:cevid_cpp:20171031203903p:plain

概要

Heroku は Heroku 自体が Metrics を提供しており、ここでサーバー全体でどんなパフォーマンスを発揮しているのかを見ることができる。しかしあくまで概要しかわからないので、具体的にどの URL のアクションが問題を起こしているのかまでは教えてくれない。そのため Scout や NewRelic のような、より詳細を見ることのできるメトリクスの Addon が存在する。

以降は Scout のスクショ見せながらの方が早いと思うので、色々と貼りながらアプリのチューニングについて解説していく。

1, 概要チャート

f:id:cevid_cpp:20171031201220p:plain

まずは直近でのレスポンスタイムや、メモリの上昇具合などをグラフで表示してくれるチャートがある。チャートとして表示する項目自体は Heroku の Metrics と何ら変わらないのだけど、Scout のすごいのは日時で限定して、その詳細を表示してくれるところにある。例えば上図のようにレスポンス速度が遅かった時間帯にフォーカスすると、具体的にどのアクションが最も遅かったのかを一発で表示してくれる。

特定の1アクションが裏でめちゃめちゃ重い処理をしていて、ユーザーがたまにしかそこにアクセスしないような場合を考えてみよう。この場合、そのアクションを実行された瞬間に一気にレスポンス速度が遅くなるし、メモリが上昇することもあるだろう。そんな時は上記の図のような感じで期間を指定しながら最も遅かったリクエストを調査していくことが可能になる。ちなみに "Slowest Resopnse Time" が現在選択されているが、その他に Largest Memory Increase がある。

2, Memory Bloat Insights

f:id:cevid_cpp:20171031201735p:plain

特定の1アクションが原因で、サーバー内のメモリが急上昇するのが Memory Bloat と呼ばれる現象だ。Scout ではそれを一発で見つけてくれる。私の経験則としては、上図のように 単一リクエストで 10M くらいだったらあまり気にする必要はないと思う。全てのリクエストで Memory Bloat が 50M 以上だったりする場合は、それは明らかに直すべきという感じで見るのがいいと思う。

じゃあ具体的にどんな原因で Memory が増えるのかってのは、以下のようなケースがある。

  • 重い DB クエリ
  • 1度に大量のクエリを発行
  • ファイルアップロード
  • blob など大容量のデータを読み込んでしまう

それぞれに最適化の方法があるので、もし原因がわかった場合には調べて対応していこう。

3, n+1 Insights

Rails において N+1 は深刻なコードミスだ。簡単にいうと、毎回 SQL のクエリを投げるコードを each の中に書いちゃった場合に発生する。

@artilces = Article.all

<% @articles.each do |article| %>
  name: <%= article.user.name %>
<% end %>

残念ながら、このコードを書いた時点で N+1 が発生してしまう。aritcle.user の時点で Article に紐づく User を View のループの中で SQL で探しに行かないといけないからだ。具体的には @artilces = Article.includes(:user).all とするのが正解だ。これでわざわざ View の中で 複数の SQL を発行しに行かなくなる。

てな対策をしろってのを Scout が教えてくれる。本来ならローカル環境で Bullet Gem を入れたりして見つけるべきことなんだけど、本番データとしてちゃんとある場合にしか見つけられないケースとかたまにあったりするので便利だ。

各アクションの分析

どのアクションが重いかわかったら、具体的にその中のどの部分が遅いのかを見ていこう。アクションの詳細にいけば、それが全てわかる。

f:id:cevid_cpp:20171031203311p:plain

今回はわかりやすいようにわざと外部への HTTP リクエストを送るコントローラーを例にしてみた。上記のように、このリクエストの大部分は HTTP が原因であることがわかる。これが例えば DB クエリが遅いってなら SQL のチューニングなどをしたり、コントローラー自体が重いってならコントローラーのロジックを再検討する必要があるということがわかるというわけだ。

終わりに

こんな感じで遅いアクションを見つけて、その原因を1つ1つ取り除いていくっていう地味だけど大事な作業が安定したサービス運営につながっていく。Scout はこの他にも DB クエリのメトリクス、Github 連携、アラート通知機能などを提供している。無料でもそれなりに原因を見つけられたりするので、まずは試しに入れてもらえたら幸いだ。課金はそれなりにサービスが運営できるようになったらでいいと思う。

こういうのって実際にそれなりの Web サービスを運営していないとわからないことなので、当てた Web サービスを作った後にはぜひ知っておいていただきたいと思う。

"このサービス重すぎて使えない" ってなった時にはもう遅いので、その悲劇が起きる前に一つずつ解決していこう。

Webフロントエンド ハイパフォーマンス チューニング

Webフロントエンド ハイパフォーマンス チューニング