54
便利なHerokuActiveRecord速度改善Tips 2015-06-06() 9回中国地方DB勉強会 IN 米子 株式会社リゾーム システム開発部 尾古 豊明

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

  • Upload
    -

  • View
    734

  • Download
    6

Embed Size (px)

Citation preview

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

便利なHerokuとActiveRecordの速度改善Tips

2015-06-06(土) 第9回中国地方DB勉強会 IN 米子株式会社リゾーム システム開発部 尾古 豊明

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

自己紹介

名前:尾古 豊明

所属:株式会社リゾーム(岡山)

TwitterID:@patorash

鳥取県大山町(旧中山町)出身。

米子東高校卒業後、愛媛大学に進学。松山で就職。

NWしてたけど25歳でPHPプログラマに強制転向。

独自フレームワーク、CakePHP、WordPressなどを経てAndroidやって、1年個人事業主やって、チーム開発がしたくなりリゾームに入社。RubyとRailsを覚える。

DBには詳しくありません!

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

実家は牧場です

和牛の飼育からお肉の通信販売

焼肉レストランを経営しています

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

春先から放牧することも

Page 5: 便利なHerokuと active recordの 速度改善tips
Page 6: 便利なHerokuと active recordの 速度改善tips
Page 7: 便利なHerokuと active recordの 速度改善tips
Page 8: 便利なHerokuと active recordの 速度改善tips

会社の話

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

とは?

ショッピングセンター(SC)・専門店向けのシステム開発やコンサルティング業務をしている会社です。

Windows系・Java・Rubyなどで自社製品の

開発を行っています。

● 顧客分析システム● デベロッパーマネジメントシステム● BOND GATE(コミュニケーションウェア)● SC GATE(SC・ショップDB)

Page 10: 便利なHerokuと active recordの 速度改善tips
Page 11: 便利なHerokuと active recordの 速度改善tips

SC GATEとは?

SCと、そのテナント(ショップ)と運営元の企業を横断的に検索・比較できるデータベースシステムです。

● SCの出店計画を立てるため● 専門店の出店計画● ライバルの動向チェック

などなど。

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

SC GATEを支える技術

● プログラミング言語 :Ruby 2.2.2● フレームワーク   :Rails 4.2.1● プラットフォーム  :Heroku● データベース    :Postgresql● ソースコード管理  :github● CSSフレームワーク :Bootstrap● AltJS :CoffeeScript● CSS :Sass● テンプレートエンジン :Slim● JSライブラリ :jQuery,Knockout

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

Ruby on Railsとは?

● 世の中のWebフレームワークで最も大きな影響を与えたであろうMVCフレークワーク

● Railsのようなフレームワークが色んなプログラミング言語で作られた○ PHP・・ CakePHP○ Java・・ SpringMVC、Play Framework○ Python・ Django

● 中でもModelを担当するActiveRecordがものすごく優秀で使いやすい

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

今日話すこと

● Herokuについて● ActiveRecordについて● PostGISについて

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

Herokuとは?

● PaaSサービス● 課金でスケーラブルな環境が手に入る● 様々なプログラミング言語をサポート● 様々なデプロイ方法(git, github,DropBox)● 制限が色々…

○ 30秒ルール○ ファイルの保存はできない等

● アドオンを追加することで、拡張可能○ データベース(Postgresql, MySQL)○ SSL○ NewRelicなど監視ツール系、ログ収集系○ メール配信系○ memcachedなどその他色々…

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

Heroku App

Heroku git

Slug(塊)

Dyno Manager

DynoDyno Dyno

コンパイル

アドオン● データベース● メール配信システム● キャッシュシステム● 状態監視サービス● スケジューラー● SSL● エラー監視サービス● ログサービス

git

Rails

git push heroku tagname:master開発者

● 固有のサーバを持たなくて済む。● Dynoの性能変更でスケールアップ、数を変更でスケールアウト● スポットでDynoの増減をすればいい(イベント時のみ増やすとか)

コード管理はgithubgit push origin develop

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

Herokuのデータベース

● Heroku Postgresqlが提供されている● MySQLはサードパーティのアドオン● HerokuでRailsアプリを作る場合は

特に制限・こだわりがなければPostgresqlがいいと思う(情報が多いから)

● 定期的にバックアップを取ってくれる● お試しの無料プラン、趣味の$9プラン、

本番環境向けのstandard, premiumなど色々ある。

● 商用だとstandard0以上オススメ($50〜)○ 最大コネクション数が100になるから

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

ActiveRecordとは?

● 超強力なO/R Mapperです。○ データベースから取得したデータが自動的にクラスのオ

ブジェクトに変換される仕組みのこと

利点● SQLを書かなくてもいい。

● マイグレーションができる。

● データベース周辺を抽象化してくれる。

● オブジェクトなので扱いやすい

欠点

● 遅い(と、よく言われる)

● メモリを大量に使う

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

利点:SQLを書かなくてもいい

SELECT * FROM articles WHERE id = 1;SELECT * FROM comments WHERE article_id = 1;のようなSQLを書かなくてもよい。結構複雑なところまで網羅できるが、拡張gemを使うとさらに便利に。

article = Article.find 1article.comments.each do |comment| p comment.titleend

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

ActiveRecordの表現力の高さ

user = User.find 1articles = Article.where(status: ‘open’, user_id: user).order(created_at: :desc).limit(10)

user = User.find 1articles = Article.open.written_by(user).recent(10)

ActiveRecordの流儀に則ってscopeを定義すると、データの絞り込みが流れるように書ける

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

利点:マイグレーションができる

DB定義の変更はリスクを伴うし、だめだった場合に戻すのが大変だった。しかし、マイグレーションが簡単になったことで気軽にDB定義の変更ができるようになった。

class AddCommentsCountToArticle < ActiveRecord::Migration def up add_column :articles, :comments_count, :integer, default: 0 end

def down remove_column :articles, :comments_count endend

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

利点:マイグレーションができる

カジュアルにテーブル定義を書き換えられる。

仕様変更しやすい。ダメでもすぐに戻せる。

テーブル定義の変更履歴がマイグレーションファイルとして残るため、

変更の反映漏れが起こる確率はかなり低くなる。

$ bin/rake db:migrate

● テーブル定義を変更する

● テーブル定義を前の状態に戻す

$ bin/rake db:rollback

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

欠点:遅い(と言われる)

● 適当にコードを書くと、DBアクセス回数が膨大になる(N+1問題)

● 大量のデータを読み込むとメモリを大量に消費する(Rubyでオブジェクトが大量に作られるため)

● Rubyでループを回すと遅い

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

N+1問題とは?

article = Article.find 1article.comments.each do |comment| p comment.user.nameend

SELECT * FROM articles WHERE id = 1;SELECT * FROM comments WHERE article_id = 1;SELECT * FROM users WHERE user_id = 1;コメントしたユーザー名の取得N回

コメント全件取得1回のDBアクセスが発生する。

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

どうすれば速くなるか?

● 1度のDBアクセスでデータを取得する(DBアクセス回数を減らす)

● 使うカラムのデータだけ取得する(取得するデータ総量を減らす、 オブジェクトを生成しない等)

● 大量のデータを一度に取得しない(生成するオブジェクトの数を減らす)

● Rubyでのループの回数を減らす(一度に取得する上限は20件まで等)

● そもそもDBにアクセスしない

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

どうすれば気付くか、減らせるか

● パフォーマンス監視ツールを使う● 検知するためのgemを使う● counter_cacheを使う● 便利なメソッドを使う● ページング用のgemを使う(kaminari)● フラグメントキャッシュを使う

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

どうすれば気付くか、減らせるか

● パフォーマンス監視ツールを使う● 検知するためのgemを使う● counter_cacheを使う● 便利なメソッドを使う● ページング用のgemを使う(kaminari)● フラグメントキャッシュを使う

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

New Relic:パフォーマンス監視

Page 29: 便利なHerokuと active recordの 速度改善tips
Page 30: 便利なHerokuと active recordの 速度改善tips

NewRelicはローカル環境も見れるhttp://localhost:3000/newrelic/

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

レスポンスタイムが一目でわかる。遅い場合は赤文字で教えてくれる。そこを速くすればいい。

Page 32: 便利なHerokuと active recordの 速度改善tips
Page 33: 便利なHerokuと active recordの 速度改善tips

どんなクエリが発行されて、どれだけ時間がかかっているかが一覧でわかる。遅い場所があれば、そのクエリを改善してみる。結果をキャッシュしてもよいのならキャッシュを試みる。そして、計測する。

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

bullet:N+1問題検出用gem

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

N+1問題とは?

article = Article.find 1article.comments.each do |comment| p comment.user.nameend

SELECT * FROM articles WHERE id = 1;SELECT * FROM comments WHERE article_id = 1;SELECT * FROM users WHERE user_id = 1;コメントしたユーザー名の取得N回

コメント全件取得1回のDBアクセスが発生する。

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

bulletがN+1問題を検出して通知。<= Comment.includes(:user)をすればいいと言ってくれてる。

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

counter_cacheを使う

関連先のデータ数をキャッシュしておく

例:記事のコメント数がいくらあるか?

SELECT * FROM articles WHERE id = 1SELECT COUNT(*) FROM comments WHERE article_id = 1;2回SQLが実行される

article = Article.find 1article.comments.count

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

counter_cacheを使う

例:記事のコメント数がいくらあるか?

comments_countカラムを定義して、

更新時にカウント数をキャッシュしておく。

SELECT * FROM articles WHERE id = 1

1回のSQLで済む

article = Article.find 1article.comments_count

Page 39: 便利なHerokuと active recordの 速度改善tips
Page 40: 便利なHerokuと active recordの 速度改善tips

counter_cacheの注意点

例えば、論理削除・無効フラグなどを使ってデータを制御している場合は、デフォルトだとその設定は無視される。

絞り込み条件も与えること。

has_many :comments

has_many :comments, -> { where(deleted: false) }

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

便利なメソッドを使う

Railsは便利だがパフォーマンスが悪い、と

長年言われ続けてきたためパフォーマンス改善のために様々なメソッドが準備されている。

● pluck● find_each● eager_load, joins, preload● to_sql● explain

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

pluck

モデルオブジェクトを生成せずに指定したカラムの

データを配列で取得する。

titles = Article.pluck(:title)titles.each do |title| puts titleend

articles = Article.allarticles.each do |article| puts article.titleend

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

find_each

大量のデータを小分けに取得してループする。

一度に大量のオブジェクトが作られないため、

メモリに優しい反面、DBへのアクセス回数は増える

Article.all.each do |article| puts article.titleend

Article.find_each do |article| puts article.titleend

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

eager_load, joins, preload

関連データをキャッシュしてDBアクセス数を減らす。

代わりにメモリを消費するので大きなテーブル同士は

やめたほうがいい。検索条件に使うだけならjoinsを使う。

article = Article.find 1article.comments.each do |comment| puts comment.contentend

article = Article.eager_load(:comments).find 1article.comments.each do |comment| puts comment.contentend

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

to_sql

ActiveRecordで組み立てて発行したSQL文を取得する。

サブクエリとして使うパターンもある。

私自身はあまり使わないが、思った通りのデータが取得できないときに、確認のためにデバッグツール上で呼ぶことがある。

query = Article.where(id: 1).to_sql

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

explain

実行計画を見ることができる。

私自身は全く使ったことがない。

Article.where(id: 1).explain

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

PostGISについて

PostGISはGISを扱うための拡張機能

GeographicInformationSystem・・・ 地理情報システム

緯度・経度・標高など

平たくいうと、Google Mapsなど地図アプリで独自

のデータを扱う際などに便利!

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

PostGISのなにが嬉しいのか?

位置情報からレコードを

検索できる

例えば・・・

● 指定した緯度・経度から

半径10km以内のレコードを取得

● 距離でソートなど

Page 49: 便利なHerokuと active recordの 速度改善tips
Page 50: 便利なHerokuと active recordの 速度改善tips
Page 51: 便利なHerokuと active recordの 速度改善tips

ActiveRecordでPostGIS

● activerecord_postgis_adapterを利用することで使える

● 2系だとRails4.2系がサポートされていなかった。スライド書き始めた時は最新が3.0.0.β5だったが、最近3.0.0がリリース

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

GISを扱う時にハマッたポイント

測地系:世界測地系・日本測地系

● 数百メートル近くずれる● activerecord_postgis_adapterでは、

世界測地系しかサポートしていない● システム的には、日本測地系のデータしか使わ

ない● 毎回、測地系変換をJS側で実行している

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

HerokuでPostGISは使えるか?

使える

● PostGISの有効化● Rails起動時にAdapter差し替え処理を追加

○ Herokuのドキュメントに書いてある

※ただし、正式サポートではない

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

以上!!