現在、Snapに書かれた小さなHaskell Webサーバーを試しています。このサーバーは、クライアントに多くのデータをロードして利用可能にします。そして、私は非常に苦労してサーバプロセスをコントロールしています。ランダムな瞬間に、プロセスは数秒から数分間CPUを大量に使用し、クライアントの要求に無関係になります。場合によっては、メモリ使用量が数百メガバイト(秒)以内に急増(時には低下することがあります)します。Haskellで5GBのヒープを制御するには?
多くのメモリを使用する、長時間実行されているHaskellプロセスでは、誰かがより安定したものにするためのいくつかの指針を与えることができればうれしいです。私は数日の間デバッグしてきました、そして、私はここで少し切望し始めています。
私のセットアップの小さな概要:私は、メモリの大(ネスト)Data.Map-似た構造へのデータのおよそ5ギガバイトを読んで、サーバの起動時に
。ネストされたマップはvalue strictで、マップ内のすべての値はすべてのフィールドが厳密に設定されたデータ型です。私は未評価のサンクが残っていないことを保証するのに多くの時間をかけました。インポート(システムの負荷によって異なります)には5〜30分かかります。奇妙なことは、連続走行の変動が予想以上に大きいことですが、それは別の問題です。
大きなデータ構造は、スナップサーバーによって生成されたすべてのクライアントスレッドによって共有される 'TVar'の内部に存在します。クライアントは、小さなクエリ言語を使用してデータの任意の部分を要求できます。データ要求の量は通常(わずか300kbかそれまで)小さく、データ構造の小さな部分にしか触れません。すべての読み取り専用要求は 'readTVarIO'を使用して行われるため、STMトランザクションは必要ありません。
サーバーは、次のフラグで起動します。+ RTS -N -I0 -qg -qb。これにより、マルチスレッドモードでサーバが起動し、アイドル時間とパラレルGCが無効になります。これはプロセスを大幅に高速化するようです。
サーバーは、ほとんど問題なく動作します。しかし、今はクライアントリクエストがタイムアウトしてCPUが100%(または100%以上)スパイクして、これを長時間続けます。一方、サーバーは要求に応答しません。
私はそのことを考えることができますいくつかの理由のCPU使用率を引き起こす可能性があります。
やるべき仕事がたくさんあるので、要求だけで多くの時間を要するが。これは、以前の実行で非常に高速であることが判明しているリクエスト(高速では20-80ms程度)で発生することがあるため、場合によっては起こりにくいです。
データが処理されてクライアントに送信される前に、計算される必要がある未評価のサンクがまだあります。これはまた、前の点と同じ理由で、起こりそうもありません。
何とかガベージコレクションが開始され、5GBのヒープ全体がスキャンされます。私はこれが多くの時間を取ることができると想像することができます。
問題は、正確に何が起こっているのか、これについて何をすべきかを理解する手がかりがないことです。インポート処理にかかる時間が長くかかるので、プロファイリングの結果は何も役に立たない。条件付きでコード内からプロファイラをオン/オフする方法はないようです。
個人的にGCが問題であると思われます。私はGHC7を使用しています.GHC7には、GCの動作方法を調整するオプションがたくさんあるようです。
一般的に非常に安定したデータを持つ大きなヒープを使用する場合、どのようなGC設定を推奨しますか?
おかげで..どのくらいのRAMこのサーバーアプリケーションを実行しているボックス – Ankur
私のマシン上に合計8GBのRAMがあります。それで十分でしょう。 –
ええ、それはページフォールトを避けるのに十分だと思われます – Ankur