【Rails入門】遅いと感じたらRailsを高速化しよう!
はじめに
Railsでアプリケーションを作っていると、「遅い」と感じることがあります。
もちろん、RailsアプリケーションはWebアプリケーションですので、ネットワークの回線速度や環境(混み具合など)などによってパフォーマンスが悪くなることもあるでしょう。
しかし、実際には、プログラムの問題で遅くなっていることも数多くあるのです。
今回は、Railsアプリケーションの使い勝手を左右する「高速化」について、注意点や改善方法など、基本的なポイントを詳しく解説いたします。
未経験でも確実にプログラミングスキルを身につけられる!
【DMM WEBCAMP】では、専属コーチが卒業まで伴走します!
✔短期間で効率的にプログラミングスキルを身につけたい
✔プログラミングを独学で進めていくのが不安
✔家での時間を有効に使ってスキルアップがしたい
といった方におすすめです!
\実践的なスキルが身に付くカリキュラム/
Railsアプリケーションだから遅い?
Railsアプリケーションは、開発効率を飛躍的に上げることが多く、そのために数多くのサービスのスタートアップなどで活用されています。
つまり、開発するための人間の数と時間が、他の環境を使うよりも少なくて済むのです。
これは、Railsが自動的に作り出す雛形のコードが、すでにもうそれだけで「使える」ものであり、機能によってはまったく修正することなく使われていることもあるためです。
Railsの環境を構築するだけで、ある程度動くことが保証されているわけですので、開発者は、Railsアプリケーションのコアの部分を気にすることなく、ビジネスに直結したコードに集中することができます。
しかし、この点こそが、Railsアプリケーションが遅くなる原因の1つになります。
確実に動く>パフォーマンス
自動的に生成されるコードは、それだけで確実に動くものであり、かつ可読性の高いものです。それがRailsの大きな利点です。
しかし、そのコードが必ずしもパフォーマンス的に最適なコードではありません。
むしろ、可読性やメンテナンス性を考慮するために、パフォーマンス的にマイナスな場合もあるのです。
○○が遅い
Railsアプリケーションは、パソコンにインストールするアプリケーションと違って、ネットワークやデータベースなど、外部的な要因によって速度低下を起こす可能性が多くあります。
もちろん、本番環境のサーバーの問題もあります。
そのため、それらにパフォーマンス問題の原因を負わせて、思考停止してしまうこともあるのです。
それでは、Railsアプリケーションのパフォーマンス向上は望めません。
以上のように、「Railsアプリケーションだから遅い」と言ってしまう原因はいくつかあります。
しかし、Railsプログラマーである以上、これらは最後の言い訳にもなりません。パフォーマンス問題の原因のほとんどは、技術的に解決できるものなのです。
非公開: 未経験から上京し、エンジニアとしてチームラボグループに転職!【WebCampPro卒業生インタビュー】Railsアプリケーションが遅い技術的な原因
では、ここからパフォーマンス問題の原因の代表的なものを紹介していきましょう。
高速化の対応を行うにあたっては、主な原因が分からなければ、効果的には対策できません。
あくまでも基本的な内容ですが、これらの原因は押さえておきましょう。
N+1問題
データベースを扱うアプリケーションでは、必ず気を付けなければいけないのが、「N+1問題」です。
N+1問題というのは、扱うデータの数に比例して、発行されるSQLの数が増えるプログラムのことです。
SQLの発行数は、基本的にはデータベースへのアクセス回数です。そして、データベースのアクセスというのは、どうしてもある程度の時間を必要とします。
そのため、ときに数万ものデータを扱うことのあるWebアプリケーションにとって、大きなパフォーマンスの低下を引き起こす重大な問題です。
特に、N+1問題が厄介なのは、開発中のテストなどで利用する程度のデータ数ではほとんど感じることができない点です。そのため、N+1問題に気付かずリリースしてしまい、本番環境になって、突然パフォーマンスが悪くなる現象に見舞われてしまうのです。
なお、関連付けしたテーブルを生成したRailsアプリケーションは、そのまま扱うと、このN+1問題を抱えたプログラムになりますので、allメソッドやjoinsメソッドではなく、includesメソッドやpreloadメソッドを使ってデータを取得するなどしなければいけません。
詳細は「【Rails入門説明書】includesについて解説」をご参照ください。
無用なアクセス
N+1問題を考慮して、SQLの発行数を減らすことで、パフォーマンスを大きく改善することができます。
しかし、それでは改善されないことも、少なくありません。
そんなときには、テーブルに格納されているデータそのものを確認してみましょう。
テーブルに格納することができるデータの型には、次のようなものがあります。
型 | 説明 |
---|---|
string | 文字列 |
text | 改行を含む長い文字列 |
integer | 整数 |
float | 浮動小数 |
decimal | 精度の高い小数 |
datetime | 日時 |
timestamp | より細かい日時 |
time | 時間 |
date | 日付 |
binary | バイナリデータ |
boolean | 真偽値 |
テーブルにはこれらのデータを格納することができるのですが、これらのデータへアクセスするためのモデル(ActiveRecordクラス)は、通常、テーブル1行分のデータを取得してから種々の処理を行います。
あるテーブルに、ビデオのタイトルとサムネイル画像、動画データが格納されているとしましょう。
このとき、ビデオのタイトルを取得しようとした場合、特に何の工夫もしなければ、モデルは1行分のデータをメモリに読み込み、その中からタイトルを抜き出すといった処理になってしまいます。
つまり、たった数バイトのタイトルを取得するために、数百MBからGBになるような動画のデータを読み込んでしまうわけです。
当然、そのデータロードの時間は非常に長く、パフォーマンスを著しく落としてしまうことになるでしょう。
そんなときは、pluckメソッドを使うなどして、カラムデータに直接アクセスする方法を検討しなければいけません。
pluckメソッドについては、「【Rails入門説明書】pluckについて解説」を参照してください。
環境の違い
上記の点を考慮してうまくプログラムを作ったとしましょう。
テストでも何も問題が見つかるがなければ、いよいよ本番環境へデプロイしてリリースとなります。
しかし、実はここにも注意しなければいけない点があるのです。
本番環境は、今まで使ってきた開発環境とは明らかに違う環境です。コンピュータの性能やセキュリティ、データベースが違うこともあります。特に、ネットワーク環境にいたっては、開発環境のような恵まれた環境であることはほとんどありません。
つまり、ただ載せ替えただけでは、思ったようなパフォーマンスが出ないことがあるのです。
そんなときには、一人ですべて対応しようとせず、素直に、専門家に確認してください。
もちろん、ネットワークスペシャリストなどであれば、自分で調整すればよいですが、ネットワークの運用については、種々のノウハウもありますし、環境によって設定方法にも違いがあります。
それらは専門家にうまく任せるようにしなければいけません。
本番環境へのデプロイ時には、必ず専門家のアドバイスを受けるようにしましょう。
「"プログラマー"という職種に興味はあるけど、何から始めていいかわからない…」 そんな悩みを持つ方も、【DMM WEBCAMP】でなら徹底サポートで確実にプログラミングスキルを身につけることができます! ✔受講生の97%が未経験者! \未経験からプログラマーを目指す方は必見!/
✔一人一人に合わせた学習計画で進められるため、仕事や学校と両立できる!
✔未経験者のために開発された独自のカリキュラムを用意!
パフォーマンスが悪くなっている場所
ここまでで、Railsアプリケーションのパフォーマンスが悪くなる原因と、簡単な対処方法を説明しました。
しかし、これらの対処方法が有効に機能するのは、パフォーマンスを悪くしている原因が分かっているからです。
どこが遅くなっているかを突き止めなければ、効果的な対処はできません。
時間のかかっている場所を見つける
Railsアプリケーション全体のパフォーマンスが落ちているときに、やみくもに高速化の手法を試しても、ほとんどの場合はうまくいきません。
まずは、「どこが足を引っ張っているのか」を突き止めて、そこから対処していかなければ、高速化の効果は薄くなってしまうでしょう。
そのための方法には、大きく分けてログを見る方法と、パフォーマンス計測用のgemを導入する方法の2つがあります。
ログを確認する
パフォーマンスの計測をするもっとも簡単な方法が、実行時のログを確認することです。
Railsは何らかのアクセスがあるたびに、必ずその処理時間をログ出力してくれています。
例えば、以下のような出力です。
[bash]Completed 200 OK in 2039ms (Views: 1949.5ms | ActiveRecord: 39.0ms)
[/bash]
このログは、以下のような意味になります。
場所 | 意味 | 注意点 |
---|---|---|
Completed 200 OK in 2039ms | レスポンスを返すまでの時間は2039ms | |
Views: 1949.5ms | 画面の生成と表示に要した時間が1949.5ms | Viewファイル内の処理すべてにかかった時間なので、レンダリングだけではない |
ActiveRecord: 39.0ms | アクションでテーブルにアクセスした時間 | ActiveRecord内でクエリの生成や実行、取得したデータの変換などの「Rubyの処理」は含まれていない |
まずは、最初の値「2039ms」に注目しましょう。これが、ユーザーがアクセスしてページが表示され終わるまでの時間を表す数値です。この数値が小さくなれば、パフォーマンスが上がったということになります。
そして、実際にどこで時間がかかっているかを見ていくわけです。
今回の例の場合は、明らかにViewで画面を表示しているのに時間がかかっています。
詳細はプログラムを見なければ分かりませんが、例えばこの画面が一覧画面だった場合は、N+1問題が発生している可能性が考えられます。
このように、ログを見ることで、問題点の「あたり」を付けることができるのです。
gemを導入する
ログでは分からない詳細な情報や、リアルタイムな時間を計測するなどしたければ、パフォーマンス計測用のgemを導入するのも悪くありません。
例えば、「rack-mini-profiler」gemを導入すれば、以下のように、ページの読み取りにかかった時間を詳細に読み取って表示してくれるようになります。
キャッシュを使う!
高速化にもいろいろな手法がありますが、最後に、非常に効果的で簡単な方法を1つ紹介しましょう。
それが、「キャッシュ」です。
キャッシュをうまく使うことができれば、応答時間を60%まで縮めることも難しくありません。
キャッシュは、データベースへのアクセスやViewでの表示など、何度も同じデータを扱う場合に、そのデータをメモリに記録しておくことで、次回以降のアクセス時間を限りなくゼロにするものです。
ただ、データを保持しておくだけで、かつRailsにはcacheという仕組みが備わっていますので、高速化と言えば、まずキャッシュを検討する人も少なくありません。
しかし、キャッシュは「過去のデータを保持している」だけですので、リアルタイムに変化する情報には使えませんし、「いくら修正しても直らない」不可解なバグの温床にもなります。
使いどころをきっちりと検討したうえで使うようにしなければいけません。
まとめ
Railsの高速化の基本的な部分について説明しました。
Railsアプリケーションは、ユーザーが操作するブラウザからのリクエストにレスポンスを返すのが主な動作ですので、そのレスポンスの速さがそのまま、ユーザビリティにつながります。
そのため、「動くプログラムを作る」ということは重要ですが、それと同じくらいパフォーマンスを重視したプログラムを作ることも考えなければいけません。
もちろん、それで可読性やメンテナンス性が低下しても意味がありません。
Railsプログラマーというのは、これらのバランスをとることで、ユーザーに最高の体験を与えることができる職業なのです。
・Railsアプリケーションは雛形のままでは、パフォーマンスよりもRailsのあるべき姿に忠実なものになっている
・Railsアプリケーションのパフォーマンスを悪くする外部要因は多数あるが、それらを原因と考えるのは最終手段
・SQLの発行数を意識してN+1問題を回避する
・データのサイズを意識してデータベースにアクセスする
・本番環境へデプロイするときは、環境の違いを考慮した設定にすること(専門家に聞くこと)
・高速化対応の最初の一手は、問題個所の特定
・ログやgemで処理速度を数値で確認できる
・最適に使えば、キャッシュは効果的な高速化ができる