11

私は最近、開発モードでうまく機能する新しい Ruby on Rails アプリケーションを立ち上げました。起動後、使用されているメモリが常に増加していることを経験しています。

New Relic、Dyno メモリ使用量からのスクリーン ダンプ

更新: New Relic からのこのスクリーン ダンプが取得されたとき。 Web dyno の再起動を 1 時間ごとにスケジュールしました (2 つの Web dyno のうちの 1 つ)。 したがって、500Mb のクラッシュ レベルには達せず、実際には少しシグソー パターンが発生します。 ただし、これによって問題がまったく解決されるわけではなく、一部の症状のみが解決されます。 ご覧のとおり、午前中はそれほど忙しくありませんが、午後はより忙しくなります。

UPDATED : New Relic からのこのスクリーン ダンプ (下の 1 つ) が取得されたとき。Web dyno の再起動を 1 時間ごとにスケジュールしました (2 つの Web dyno のうちの 1 つ)。したがって、500Mb のクラッシュ レベルには達せず、実際には少しシグソー パターンが発生します。ただし、これによって問題がまったく解決されるわけではなく、一部の症状のみが解決されます。ご覧のとおり、午前中はそれほど忙しくありませんが、午後はより忙しくなります。私は 11.30 に小さな詳細をアップロードしました。統計にそのように表示されていても、問題に影響を与えることはできませんでした。

グラフが AVG メモリを示していても、増加し続けるのは MIN メモリであることにも注意してください。グラフで一時的にグラフが下がったように見える場合でも、最小メモリは変わらないか、増加します。MINメモリーが減ることはありません!

アプリは (dyno 再起動なしで) Heroku で最大レベルに達するまでメモリを増やし、アプリは実行期限切れタイプのエラーでクラッシュします。

私は優れたプログラマーではありませんが、この種の問題が発生することなく、以前にいくつかのアプリを作成しました。

実行されたトラブルシューティング

A. 問題は application_controller の before_filter 内にあると思っていましたが (アプリケーション コントローラーの変数が Rails でメモリ リークを引き起こしますか? )、それは問題ではありませんでした。

B. oink をインストールしましたが、(まったく) 結果が得られません。oink.log を作成しますが、「heroku run oink -m log/oink.log」を実行しても、しきい値に関係なく結果が得られません。

C. bleak_house を試しましたが、非推奨でインストールできませんでした

D. このトピックのほとんどの記事をグーグル検索して読んだことがありますが、賢明ではありません。

E. memprof をテストしたいのですが、インストールできません (Ruby 1.9x を持っていて、1.8x にダウングレードする方法がよくわかりません)。

私の質問:

Q1. 私が本当に知りたいのは、リクエストごとに増加している変数の名前、または少なくともどのコントローラーが最も多くのメモリを使用しているかです。

Q2. 以下のコードのコントローラーはメモリを増やしますか?

related_feed_categories = []
@gift.tags.each do |tag|
  tag.category_connections.each do |cc|
    related_feed_categories << cc.category_from_feed
  end
end

(申し訳ありませんが、SO は何らかの理由でコードを読みやすいように再フォーマットしません)。

後で「related_feed_categories = nil」でrelated_feed_categoriesを「殺す」必要がありますか、それともガベージコレクターがそれを処理しますか?

Q3. 私が探すべき主なものは何ですか?今のところ、私はそれをまったく絞り込むことはできません。コードのどの部分を詳しく調べる必要があるのか​​ わかりません。また、何を探すべきか本当にわかりません。

Q4. 本当に問題を解決できない場合。コードを送って問題を見つけてもらうことができるオンライン コンサルティング サービスはありますか?

ありがとう!

更新。コメントを受け取った後、それはセッションに関係している可能性があります。これは、悪いと思われるコードの一部です。

# Create sessions for last generation
friend_data_arr = [@generator.age, @generator.price_low, @generator.price_high]
friend_positive_tags_arr = []
friend_negative_tags_arr = []
friend_positive_tags_arr << @positive_tags
friend_negative_tags_arr << @negative_tags    
session["last_generator"] = [friend_data_arr, friend_positive_tags_arr, friend_negative_tags_arr]

# Clean variables
friend_data_arr = nil
friend_positive_tags_arr = nil
friend_negative_tags_arr = nil

generator#show コントローラで使用されます。私のギフト生成エンジンによっていくつかのギフトが生成されたら、入力をセッションに保存します (後でその情報を使用したい場合に備えて)。これらのセッションを強制終了したり期限切れにしたりすることは決してないので、メモリが増加する可能性があります。

再更新: このコードを削除しましたが、メモリはまだ増加しているので、この部分ではないと思いますが、同様のコードでエラーが発生する可能性がありますか?

4

2 に答える 2

5

related_feed_categories がこれを引き起こす可能性は低いです。

多くのファイルを使用していますか?

セッションデータはどのくらいの期間保持されますか? e コマース サイトをお持ちのようですが、オブジェクトをセッションに保持していますか?

基本的には、ファイル、セッション、またはサーバーがクラッシュしたときにフラッシュされる一時データの増加 (memcache ?) だと思います。

真夜中はお客さんも少ないと思います。ピーク時に同じメモリ チャートを投稿できますか?

これは、この問題に関連している可能性があります:空の Rails アプリでメモリが無期限に増加する

アップデート :

Rails はすべてのデータをクライアント側に保存するわけではありません。デフォルトのストアは覚えていませんが、cookie::store を選択しない限り、Rails は session_id などのデータのみを送信します。

これらはセッションに関するいくつかのガイドラインであり、ActiveRecord::SessionStore がパフォーマンスの目的で最良の選択であるようです。また、大きなオブジェクトやシークレット データをセッションに保持しないでください。セッションの詳細はこちら: http://guides.rubyonrails.org/security.html#what-are-sessions

2.9のパートでは、一定期間使用されていないセッションを破棄する説明があります。

オブジェクトをセッションに保存する代わりに、検索結果を提供する URL を保存することをお勧めします。データベースに保存することもできます。これにより、顧客にいくつかの調査を保存したり、デフォルトで最後に使用したものをロードしたりできます。

しかし、これらの段階では、セッションが原因であるかどうかはまだ完全にはわかりません. 確実にするために、テストサーバーを試して、期限切れのセッションでアプリケーションのストレステストを行うことができます。基本的に、多数のセッションを作成すると、おそらく 20 分後にレールがセッションを抑制しなければならなくなります。メモリ消費量に違いが見つかれば、絞り込むことができます。

最初のケース: セッションの有効期限が切れるとメモリが大幅に低下します。これはセッションに関連していることがわかります。

2 番目のケース: メモリはより速い速度で増加しますが、セッションの有効期限が切れても低下しません。これはユーザー関連であり、セッション関連ではないことがわかっています。

3 番目のケース : 何も変化しない (通常はメモリが増加する) ため、ユーザー数に依存しないことがわかります。しかし、何がこれを引き起こしているのかわかりません。

ストレス テストとは、実際にはストレス テストではなく、かなりの数のセッションを意味します。必要なセッション数は、平均ユーザー数によって異なります。アプリがクラッシュする前に 50 人のユーザーがいた場合、20 ~ 30 のセッションが重要になる可能性があります。したがって、手動でそれらを持っている場合は、より高い有効期限制限を構成してください。メモリ消費の違いを探しているだけです。

更新 2:

したがって、これはおそらくメモリリークです。そのため、オブジェクト スペースを使用します。現在使用されているすべてのオブジェクトを表示する count_objects メソッドがあります。それは物事を狭めるべきです。メモリがすでに大幅に増加している場合に使用します。

それ以外の場合は、メモリ リークを見つけることができる宝石である bleak_house がありますが、メモリ リーク用の ruby​​ ツールは Java ツールほど効率的ではありませんが、試してみる価値はあります。

GitHub : https://github.com/evan/bleak_house

更新 3 :

これは説明かもしれませんが、これは実際にはメモリリークではありませんが、メモリが増加します: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-対サービス拒否/

つまり、シンボルは ruby​​ を再起動するまでメモリに保持されます。そのため、シンボルがランダムな名前で作成されると、アプリがクラッシュするまでメモリが増加します。これは文字列では発生せず、GCed です。

少し古いですが、ruby 1.9.x で有効です これを試してください: Symbol.all_symbols.size

更新 4:

したがって、シンボルはおそらくメモリリークです。今でも、それがどこで発生するかを見つける必要があります。Symbol.all_symbols を使用します。それはあなたにリストを与えます。これをどこかに保存し、新しい配列との差分を作成して、何が追加されたかを確認できると思います。

それは i18n かもしれませんし、i18n のように暗黙的に生成されるものかもしれません。とにかく、これはおそらく名前にランダムなデータを含むシンボルを生成しています。そして、これらのシンボルは二度と使用されません。

于 2012-09-27T14:13:30.223 に答える
1

が文字列 (またはシンボル) を返すと仮定するとcategory_from_feed、300MB の増加はほとんどありません。これをプロファイリングすることで、大まかにこれに到達できます。

4_000_000.times {related_feed_categories << "Loooooooooooooong string" }

このスニペットでは、メモリ使用量が約 110MB 増加します。

ファイルを読み取って閉じないDB接続またはメソッドを調べます。フィードに関連していることがわかります。これはおそらく、XML を使用している可能性があることを意味します。それも出発点になり得ます。


これはコメントで見栄えが悪いため、これを回答として投稿します:/

于 2012-09-27T13:44:32.180 に答える