Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

便利なHerokuと active recordの 速度改善tips

3,092 views

Published on

第9回中国地方DB勉強会での発表資料です。

Published in: Technology
  • Be the first to comment

便利なHerokuと active recordの 速度改善tips

  1. 1. 便利なHerokuと ActiveRecordの 速度改善Tips 2015-06-06(土) 第9回中国地方DB勉強会 IN 米子 株式会社リゾーム システム開発部 尾古 豊明
  2. 2. 自己紹介 名前:尾古 豊明 所属:株式会社リゾーム(岡山) TwitterID:@patorash 鳥取県大山町(旧中山町)出身。 米子東高校卒業後、愛媛大学に進学。松山で就職。 NWしてたけど25歳でPHPプログラマに強制転向。 独自フレームワーク、CakePHP、WordPressなどを経て Androidやって、1年個人事業主やって、チーム開発がしたくな りリゾームに入社。RubyとRailsを覚える。 DBには詳しくありません!
  3. 3. 実家は牧場です 和牛の飼育からお肉の通信販売 焼肉レストランを経営しています
  4. 4. 春先から放牧することも
  5. 5. 会社の話
  6. 6. とは? ショッピングセンター(SC)・専門店向けのシステム 開発やコンサルティング業務をしている会社です。 Windows系・Java・Rubyなどで自社製品の 開発を行っています。 ● 顧客分析システム ● デベロッパーマネジメントシステム ● BOND GATE(コミュニケーションウェア) ● SC GATE(SC・ショップDB)
  7. 7. SC GATEとは? SCと、そのテナント(ショップ)と運営元の企業を横 断的に検索・比較できるデータベースシステムで す。 ● SCの出店計画を立てるため ● 専門店の出店計画 ● ライバルの動向チェック などなど。
  8. 8. SC GATEを支える技術 ● プログラミング言語 :Ruby 2.2.2 ● フレームワーク   :Rails 4.2.1 ● プラットフォーム  :Heroku ● データベース    :Postgresql ● ソースコード管理  :github ● CSSフレームワーク :Bootstrap ● AltJS :CoffeeScript ● CSS :Sass ● テンプレートエンジン :Slim ● JSライブラリ :jQuery,Knockout
  9. 9. Ruby on Railsとは? ● 世の中のWebフレームワークで最も大きな影響 を与えたであろうMVCフレークワーク ● Railsのようなフレームワークが色んなプログラ ミング言語で作られた ○ PHP・・ CakePHP ○ Java・・ SpringMVC、Play Framework ○ Python・ Django ● 中でもModelを担当するActiveRecordが ものすごく優秀で使いやすい
  10. 10. 今日話すこと ● Herokuについて ● ActiveRecordについて ● PostGISについて
  11. 11. Herokuとは? ● PaaSサービス ● 課金でスケーラブルな環境が手に入る ● 様々なプログラミング言語をサポート ● 様々なデプロイ方法(git, github,DropBox) ● 制限が色々… ○ 30秒ルール ○ ファイルの保存はできない等 ● アドオンを追加することで、拡張可能 ○ データベース(Postgresql, MySQL) ○ SSL ○ NewRelicなど監視ツール系、ログ収集系 ○ メール配信系 ○ memcachedなどその他色々…
  12. 12. Heroku App Heroku git Slug(塊) Dyno Manager DynoDyno Dyno コンパイル アドオン ● データベース ● メール配信システム ● キャッシュシステム ● 状態監視サービス ● スケジューラー ● SSL ● エラー監視サービス ● ログサービス git Rails git push heroku tagname:master開発者 ● 固有のサーバを持たなくて済む。 ● Dynoの性能変更でスケールアップ、数を変更でスケールアウト ● スポットでDynoの増減をすればいい(イベント時のみ増やすとか) コード管理はgithub git push origin develop
  13. 13. Herokuのデータベース ● Heroku Postgresqlが提供されている ● MySQLはサードパーティのアドオン ● HerokuでRailsアプリを作る場合は 特に制限・こだわりがなければ Postgresqlがいいと思う(情報が多いから) ● 定期的にバックアップを取ってくれる ● お試しの無料プラン、趣味の$9プラン、 本番環境向けのstandard, premiumなど 色々ある。 ● 商用だとstandard0以上オススメ($50〜) ○ 最大コネクション数が100になるから
  14. 14. ActiveRecordとは? ● 超強力なO/R Mapperです。 ○ データベースから取得したデータが自動的にクラスのオ ブジェクトに変換される仕組みのこと 利点 ● SQLを書かなくてもいい。 ● マイグレーションができる。 ● データベース周辺を抽象化してくれる。 ● オブジェクトなので扱いやすい 欠点 ● 遅い(と、よく言われる) ● メモリを大量に使う
  15. 15. 利点:SQLを書かなくてもいい SELECT * FROM articles WHERE id = 1; SELECT * FROM comments WHERE article_id = 1; のようなSQLを書かなくてもよい。結構複雑なところまで網羅で きるが、拡張gemを使うとさらに便利に。 article = Article.find 1 article.comments.each do |comment| p comment.title end
  16. 16. ActiveRecordの表現力の高さ user = User.find 1 articles = Article.where(status: ‘open’, user_id: user).order (created_at: :desc).limit(10) user = User.find 1 articles = Article.open.written_by(user).recent(10) ActiveRecordの流儀に則ってscopeを定義すると、データの絞 り込みが流れるように書ける
  17. 17. 利点:マイグレーションができる DB定義の変更はリスクを伴うし、だめだった場合に戻すのが大 変だった。しかし、マイグレーションが簡単になったことで気軽に DB定義の変更ができるようになった。 class AddCommentsCountToArticle < ActiveRecord::Migration def up add_column :articles, :comments_count, :integer, default: 0 end def down remove_column :articles, :comments_count end end
  18. 18. 利点:マイグレーションができる カジュアルにテーブル定義を書き換えられる。 仕様変更しやすい。ダメでもすぐに戻せる。 テーブル定義の変更履歴が マイグレーションファイルとして残るため、 変更の反映漏れが起こる確率はかなり低くなる。 $ bin/rake db:migrate ● テーブル定義を変更する ● テーブル定義を前の状態に戻す $ bin/rake db:rollback
  19. 19. 欠点:遅い(と言われる) ● 適当にコードを書くと、DBアクセス回数が膨大 になる(N+1問題) ● 大量のデータを読み込むとメモリを大量に消費 する(Rubyでオブジェクトが大量に作られるた め) ● Rubyでループを回すと遅い
  20. 20. N+1問題とは? article = Article.find 1 article.comments.each do |comment| p comment.user.name end SELECT * FROM articles WHERE id = 1; SELECT * FROM comments WHERE article_id = 1; SELECT * FROM users WHERE user_id = 1; コメントしたユーザー名の取得N回 コメント全件取得1回 のDBアクセスが発生する。
  21. 21. どうすれば速くなるか? ● 1度のDBアクセスでデータを取得する (DBアクセス回数を減らす) ● 使うカラムのデータだけ取得する (取得するデータ総量を減らす、  オブジェクトを生成しない等) ● 大量のデータを一度に取得しない (生成するオブジェクトの数を減らす) ● Rubyでのループの回数を減らす (一度に取得する上限は20件まで等) ● そもそもDBにアクセスしない
  22. 22. どうすれば気付くか、減らせるか ● パフォーマンス監視ツールを使う ● 検知するためのgemを使う ● counter_cacheを使う ● 便利なメソッドを使う ● ページング用のgemを使う(kaminari) ● フラグメントキャッシュを使う
  23. 23. どうすれば気付くか、減らせるか ● パフォーマンス監視ツールを使う ● 検知するためのgemを使う ● counter_cacheを使う ● 便利なメソッドを使う ● ページング用のgemを使う(kaminari) ● フラグメントキャッシュを使う
  24. 24. New Relic:パフォーマンス監視
  25. 25. NewRelicはローカル環境も見れる http://localhost:3000/newrelic/
  26. 26. レスポンスタイムが一目でわかる。 遅い場合は赤文字で教えてくれる。 そこを速くすればいい。
  27. 27. どんなクエリが発行されて、どれだけ時間がかかっているかが一覧でわかる。 遅い場所があれば、そのクエリを改善してみる。結果をキャッシュしてもよいのなら キャッシュを試みる。そして、計測する。
  28. 28. bullet:N+1問題検出用gem
  29. 29. N+1問題とは? article = Article.find 1 article.comments.each do |comment| p comment.user.name end SELECT * FROM articles WHERE id = 1; SELECT * FROM comments WHERE article_id = 1; SELECT * FROM users WHERE user_id = 1; コメントしたユーザー名の取得N回 コメント全件取得1回 のDBアクセスが発生する。
  30. 30. bulletがN+1問題を検出して通知。 <= Comment.includes(:user)をすればいいと言ってくれてる。
  31. 31. counter_cacheを使う 関連先のデータ数をキャッシュしておく 例:記事のコメント数がいくらあるか? SELECT * FROM articles WHERE id = 1 SELECT COUNT(*) FROM comments WHERE article_id = 1; 2回SQLが実行される article = Article.find 1 article.comments.count
  32. 32. counter_cacheを使う 例:記事のコメント数がいくらあるか? comments_countカラムを定義して、 更新時にカウント数をキャッシュしておく。 SELECT * FROM articles WHERE id = 1 1回のSQLで済む article = Article.find 1 article.comments_count
  33. 33. counter_cacheの注意点 例えば、論理削除・無効フラグなどを使ってデータ を制御している場合は、デフォルトだとその設定は 無視される。 絞り込み条件も与えること。 has_many :comments has_many :comments, -> { where(deleted: false) }
  34. 34. 便利なメソッドを使う Railsは便利だがパフォーマンスが悪い、と 長年言われ続けてきたためパフォーマンス改善の ために様々なメソッドが準備されている。 ● pluck ● find_each ● eager_load, joins, preload ● to_sql ● explain
  35. 35. pluck モデルオブジェクトを生成せずに指定したカラムの データを配列で取得する。 titles = Article.pluck(:title) titles.each do |title| puts title end articles = Article.all articles.each do |article| puts article.title end
  36. 36. find_each 大量のデータを小分けに取得してループする。 一度に大量のオブジェクトが作られないため、 メモリに優しい反面、DBへのアクセス回数は増える Article.all.each do |article| puts article.title end Article.find_each do |article| puts article.title end
  37. 37. eager_load, joins, preload 関連データをキャッシュしてDBアクセス数を減らす。 代わりにメモリを消費するので大きなテーブル同士は やめたほうがいい。検索条件に使うだけならjoinsを使う。 article = Article.find 1 article.comments.each do |comment| puts comment.content end article = Article.eager_load(:comments).find 1 article.comments.each do |comment| puts comment.content end
  38. 38. to_sql ActiveRecordで組み立てて発行したSQL文を取得する。 サブクエリとして使うパターンもある。 私自身はあまり使わないが、思った通りのデータが取得できな いときに、確認のためにデバッグツール上で呼ぶことがある。 query = Article.where(id: 1).to_sql
  39. 39. explain 実行計画を見ることができる。 私自身は全く使ったことがない。 Article.where(id: 1).explain
  40. 40. PostGISについて PostGISはGISを 扱うための拡張機能 Geographic Information System・・・ 地理情報システム 緯度・経度・標高など 平たくいうと、Google Mapsなど地図アプリで独自 のデータを扱う際などに便利!
  41. 41. PostGISのなにが嬉しいのか? 位置情報からレコードを 検索できる 例えば・・・ ● 指定した緯度・経度から 半径10km以内のレコードを取得 ● 距離でソートなど
  42. 42. ActiveRecordでPostGIS ● activerecord_postgis_adapterを利用すること で使える ● 2系だとRails4.2系がサポートされていなかっ た。スライド書き始めた時は最新が 3.0.0.β5だったが、最近3.0.0がリリース
  43. 43. GISを扱う時にハマッたポイント 測地系:世界測地系・日本測地系 ● 数百メートル近くずれる ● activerecord_postgis_adapterでは、 世界測地系しかサポートしていない ● システム的には、日本測地系のデータしか使わ ない ● 毎回、測地系変換をJS側で実行している
  44. 44. HerokuでPostGISは使えるか? 使える ● PostGISの有効化 ● Rails起動時にAdapter差し替え処理を追加 ○ Herokuのドキュメントに書いてある ※ただし、正式サポートではない
  45. 45. 以上!!

×