6

私の仕事では、C# 2003 で記述された 6 つの Windows サービスを担当しています。これらの各サービスには、約 1 分ごとに起動するタイマーが含まれており、ここで作業の大部分が行われます。

私の問題は、これらのサービスが実行されると、実行する意味のある作業がなくても (つまり、単にアイドリングしてデータベースを調べているだけである場合でも)、ループの反復ごとに CPU 時間を消費し始めることです。何かをするために)。起動時に、各サービスは 4 つの CPU の平均 (約) 2 ~ 3% を使用しますが、これは問題ありません。24 時間後、各サービスはループの実行中にプロセッサ全体を消費します。

誰でも助けることができますか?何が原因なのか途方に暮れています。私たちの現在の解決策は、サービスを 1 日 1 回再起動することです (サービスは自動的にシャットダウンし、スクリプトはサービスがオフラインであることを認識し、午前 3 時頃に再起動します)。しかし、これは長期的な解決策ではありません。私の懸念は、サービスが忙しくなるにつれて、1 日に 1 回再起動するだけでは十分ではないかもしれないということです...しかし、サービスが忙しくなるにつれて、かなりの起動ペナルティがあるため (それらはすべてデータ アクセスに NHibernate を使用します)、まさに私たちがしていないことです。やりたいことは、より頻繁に再起動することです。


@akmad: 確かに、それは非常に難しいです。

  1. はい、分離して実行されているサービスは、時間の経過とともに同じ症状を示します。
  2. いいえ、そうではありません。私たちはそれを見てきました。これは、午前 10 時または午後 6 時、または真夜中に発生する可能性があります。一貫性がない。
  3. 私たちはそうします。そして彼らは。サービスは本来あるべきことを正確に行っており、それ以外には何もしていません。
  4. 残念ながら、それには、サービスが CPU を使い果たす正確な時期を事前に把握しておく必要があります。これは、予測不可能なスケジュールで発生し、すぐに発生することはありません... これにより、状況が二重に難しくなります。デバッグの問題を考えずに問題を解決します。
  5. いいえ、かなり一貫した量の RAM を使用しています (マシンの 4GB のうち、それぞれ約 60 ~ 80MB)。

良い提案ですが、ご安心ください。通常のトラブルシューティングをすべて試しました。私が望んでいるのは、これが誰かが知っているかもしれない .NET の問題であり、私たちが解決に取り組むことができるということです。私の上司の解決策 (これは絶対に実装したくありません) は、日中にサービスを再起動するために複数回保持するフィールドをデータベースに配置することです。 . 私は必死に本当の問題の原因を探しています。なぜなら、その解決策は約 6 か月で大惨事になるからです。


@Yaakov Ellis: それぞれ異なる機能を持っています。1 つは、オフサイトのどこかにある Oracle データベースからレコードを読み取ります。別のものはそれらの記録を処理し、それらの記録に属するファイルを私たちのシステムに転送します。3 つ目は、これらのファイルをチェックして、期待どおりであることを確認します。もう 1 つは、ディスク容量 (十分な容量があること) などを常にチェックし、他のサーバーが稼働していることを確認するためにポーリングする保守サービスです。1 つは、これらの他のすべてが実行され、ジョブを実行していることを確認するためだけに実行され、エラーを監視および報告し、システム全体を 24 時間稼働させ続けるために失敗したものはすべて再起動します。

したがって、あなたが何を求めていると思うかを尋ねているのであれば、いいえ、これらすべてのサービスが行う共通のこと (NHibernate を介したデータベース アクセスを除く) は、潜在的な問題として指摘できるものではありません。残念ながら、それが実際の問題であることが判明した場合 (それほど驚くことではありません)、全体が台無しになる可能性があります。最終的には、単純な SQL ですべてを書き直すことになります。ガベージ コレクターの問題か、NHibernate よりも扱いやすいものであることを願っています。


@ジョシュダン:秘密はありません。私が言ったように、私たちはすべての通常のトラブルシューティングを試みました. プロファイリングは役に立ちませんでした。使用しているプロファイラーは、CPU 使用率が高いときに実際に実行されていたコードを指すことができませんでした。これらのサービスは、この問題を探して約 1 か月前にバラバラになりました。コードのすべてのセクションを分析して、コードに問題があるかどうかを突き止めました。私は宿題をしていないので、ここで尋ねているわけではありません。これが、サービスが予想よりも多くの作業を行っているという単純なケースであれば、それは捕らえられていたでしょう.

ここでの問題は、ほとんどの場合、サービスがまったく何もしていないにもかかわらず、4 つの CPU コアの 25% 以上を消費していることです。実行する作業が見つからず、ループを終了して待機しています。次の繰り返し。これは文字通り、CPU 時間をほとんど消費しないはずです。

これは、2 日間 (変化のない環境で) 行う作業がないサービスで、私たちが目にしている動作の例です。これは先週キャプチャされました:

1 日目、午前 8 時: 平均 CPU 使用率は約 3%
1 日目、午後 6 時: 平均。CPU 使用率は約 8%
2 日目、午前 7 時: 平均 CPU 使用率は約 20%
2 日目、午前 11 時: 平均。CPU使用率約30%

これについて考えられるありふれた理由をすべて検討した結果、ここでこの質問をしたのは、(当然のことながら、結果的には) もっと革新的な答え (Ubiguchi のようなもの)、または私が持っていなかったものへのポインタが得られるだろうと考えたからです。 tは考えました (Ian の提案のように)。


では、CPU スパイクは、タイマー コールバックの直前、タイマー コールバック内、またはタイマー コールバックの直後に発生しますか?

勘違いしている。これはスパイクではありません。もしそうなら、問題はありません。私はスパイクを扱うことができます。しかし、そうではありません... CPU使用率は一般的に上昇しています。サービスが何もしていないときでも、次のタイマー ヒットを待ちます。サービスが起動すると、物事は素晴らしく穏やかで、グラフは期待どおりに見えます...通常、使用率は0%で、NHibernateがデータベースにヒットするか、サービスが些細な量の作業を行うと、10%に急増します. しかし、これは、プロセスの実行中は常に全体で 25% (やりすぎるとそれ以上) の使用量に増加します。

これにより、Ian の提案が論理的な特効薬になりました (NHibernate は、ユーザーが見ていないときに多くのことを実行します)。悲しいかな、私は彼のソリューションを実装しましたが、効果はありませんでした (これを証明するものはありませんが、実際には事態が悪化したと思います...平均的な使用法ではるかに速く上がるようになりました)。NHibernate の「セクション」を削除することは (推奨されるように) 実行できないことに注意してください。これは、サービス内のコードの約 90% を削除することになり、タイマーを問題として除外できるようになるためです (私は絶対にそうするつもりです)。試してみてください)、しかし、問題として NHibernate を除外することはできません。NHibernate がこれを引き起こしている場合、実装されている危険な修正 (以下を参照) は、The Way The System Works になる必要があるためです。私たちはこのプロジェクトで NHibernate に大きく依存しているため、PM はそれが解決できない構造上の問題を引き起こしていることを受け入れません。

質問に絶望感を感じました - 小さな奇跡がなければ、あなたの問題は続くでしょう

そのように外れることを意味しないでください。現時点では、サービスは毎日再起動されています (1 日の任意の時間数を入力してシャットダウンして再起動するオプションがあります)。これにより問題にパッチが適用されますが、運用マシンに移行すると長期的な解決策にはなりません。そして忙しくなり始めます。私が修正するか、PM がこの制約を維持するかにかかわらず、問題は継続しません。明らかに、私は実際の修正を実装したいと考えていますが、最初のテストではその理由が明らかにならず、サービスはすでに広範囲にレビューされているため、PM は修正に時間を費やすよりもむしろ複数回再起動することを望んでいます。 . それは完全に私の手に負えないことであり、あなたが話していた奇跡を、それ以外の場合よりも重要なものにしています.

これは非常に興味深いものです (プロファイラーを信頼している限り)。

私はしません。しかし、これらは Windows 2000 マシン上で実行される .NET 1.1 で記述された Windows サービスであり、危険な Nant スクリプトによってデプロイされ、データベース アクセスに古いバージョンの NHibernate を使用します。そのマシンには、私が実際に信頼していると言えるものはほとんどありません。

4

7 に答える 7

3

ここから始めます:

  1. Process Explorerを取得し、JIT の %Time、GC の %Time、CPU サイクル デルタ、CPU 時間、CPU %、およびスレッドを表示します。
  2. カーネルとユーザーの時間、およびいくつかの代表的なスタック トレースも必要ですが、スナップショットを取得するには [プロパティ] をクリックする必要があると思います。
  3. 前後のショットを比較します。

可能性に関するいくつかの考え:

  • 過剰な GC (% Time in GC が上昇します。また、Perfmon GC および CPU カウンターも対応します)
  • 過剰なスレッドと関連するコンテキスト スイッチ (アップするスレッドの数)
  • ポーリング (スタック トレースは一貫して単一の関数でキャッチされます)
  • 過度のカーネル時間 (カーネル時間が長い - CPU の使用率が高い場合、タスク マネージャーはカーネル時間の数値を大きく表示します)
  • 例外 (PE .NET タブの Exceptions throws が高くなり、さらに高くなります。Perfmon カウンターもあります)
  • ウイルス/ルートキット (OK、これは最後の溝のシナリオです。ただし、タスクマネージャーから隠れるルートキットを構築することは可能です。十分に狡猾であれば、避けられない CPU 使用率を別のプロセスに割り当てることができると思います。さらに、上記のすべてを除外した場合、私は今アイデアがありません)
于 2008-08-28T16:27:51.647 に答える
3

NHibernate を使用しているとおっしゃいましたが、NHibernate セッションを適切な時点 (各反復の終わりなど) で閉じていますか?

そうでない場合、メモリにロードされるオブジェクト マップのサイズは時間の経過とともに徐々に増加し、各セッション フラッシュはますます多くの CPU 時間を消費します。

于 2008-08-26T12:06:59.793 に答える
2

問題を細かくハックすることをお勧めします。
まず、問題を100%迅速に再現する方法を見つけます。タイマーを下げて、サービスがより頻繁に起動するようにします(たとえば、通常の10倍の速さ)。問題が10倍速く発生する場合、それは反復回数に関連しており、リアルタイムやサービスによって実行される実際の作業には関連していません)。そして、あなたは一日一回よりも速く次のステップを行うことができるでしょう。
次に、実際の作業コードをすべてコメントアウトし、サービス、タイマー、および同期メカニズムのみを許可します。それでも問題が発生する場合は、コードのその部分にあるよりも問題が発生します。そうでない場合は、コメントアウトしたコードを一度に1つずつ追加し始めます。最終的には、コードのどの部分が問題を引き起こしているのかを突き止める必要があります。

于 2008-08-25T16:40:06.243 に答える
2

未知のアプリケーションをリモートでデバッグするのは明らかに非常に困難です...しかし、ここに私が見ているいくつかのことがあります:

  1. 一度に 1 つのサービスのみを実行するとどうなりますか? まだスローダウンが見られますか?これは、サービス間に何らかの競合があることを示している可能性があります。
  2. サービスの実行時間に関係なく、問題は常にほぼ同時に発生しますか? これは、他の何か (バックアップ、ウイルス スキャンなど) がマシン (またはデータベース) 全体の速度を低下させていることを示している可能性があります。
  3. サービスが必要な頻度でのみ機能していることを確認するためのロギングまたはその他のメカニズムはありますか?
  4. 短期間でパフォーマンスの低下が見られる場合は、サービスをしばらく実行してから、プロファイラーをアタッチして、何が CPU を固定しているのかを正確に確認してください。
  5. メモリ使用量については何も言及していません。サービスに関するこのような情報はありますか? RAM のほとんどを使い果たし、ディスクがゴミ箱に移動したり、同様の問題が発生したりする可能性があります。

頑張ってください!

于 2008-08-25T15:24:36.677 に答える
1

「恐れ入りますが、この回答は参考になる方向性を示唆しているだけですが、.NET Windows サービスで同様の問題を見てきたので、参考になるかもしれない考えがいくつかあります。

私の最初の提案は、サービスがメモリを処理する方法、またはおそらく管理されていないメモリを処理する方法にバグがある可能性があるということです。前回同様の問題を追跡したところ、静的メモリ内の管理されていないオブジェクトに格納されたハンドルを使用していたサード パーティの OSS ライブラリが判明しました。サービスの実行時間が長くなるほど、サービスが取得するハンドルが増え、プロセスの CPU パフォーマンスが急激に低下しました。この種の問題を解決して、タイマー呼び出しの間にサービスがメモリに何も保存しないようにする方法。ただし、サード パーティのライブラリが静的メモリを使用している場合は、タイマー呼び出し用のアプリ ドメインを作成して破棄するなどの巧妙な操作が必要になる場合があります。処理が完了すると、アプリのドメイン (およびその静的メモリ)。

同様の状況で私が見たもう 1 つの問題は、タイマー同期コードが疑わしいというものでした。これにより、実際には、複数のスレッドが処理コードを一度に実行できるようになりました。コードをデバッグしたところ、1 番目のスレッドが 2 番目のスレッドをブロックしており、2 番目のスレッドが開始されるまでに 3 番目のスレッドがブロックされていることがわかりました。時間が経つにつれて、ブロックはますます長く続き、CPU 使用率はトップに向かっていました。この問題を修正するために使用した解決策は、適切な同期コードを実装して、ブロックされない場合にのみタイマーが別のスレッドを開始するようにすることでした。

これがお役に立てば幸いですが、私の考えが両方とも赤いニシンである場合は、前もってお詫び申し上げます。

于 2008-08-25T15:37:33.460 に答える
1

タイマーのスレッドの問題のようです。1 つの作業単位が別のワーカー スレッドで実行されている別の作業をブロックしている可能性があり、タイマーが起動するたびにスタックが発生します。または、予想よりも長く生きて働いているインスタンスがあるかもしれません。

タイマーをリファクタリングすることをお勧めします。ThreadPool で作業をキューに入れる単一のスレッドに置き換えます。スレッドを Sleep() して、新しい作業を探す頻度を制御できます。これがコードがマルチスレッド化されている唯一の場所であることを確認してください。他のすべてのオブジェクトは、処理の準備が整ったときにインスタンス化され、その処理が完了した後に破棄される必要があります。マルチスレッド コードでは STATE IS THE ENEMY です。

設計に欠けているもう 1 つの領域は、何かを行うためにリソースをポーリングしている複数のサービスがあることです。それらを単一のサービスに統合することをお勧めします。彼らは別々のことをしているかもしれませんが、協調して働いています。メソッド呼び出しの代わりにファイルシステム、データベースなどを使用しているだけです。また、2003年?すみません。

于 2008-08-25T15:46:13.377 に答える
0

良い提案ですが、ご安心ください。通常のトラブルシューティングをすべて試しました。私が望んでいるのは、これが誰かが知っているかもしれない .NET の問題であり、私たちが解決に取り組むことができるということです。

根本的な原因がどれほど奇妙であっても、通常のトラブルシューティング手順が問題を特定するための最善の策であると私は感じています.

これはパフォーマンスの問題であるため、適切な測定値は非常に重要です。全体的なプロセスの CPU 使用率は、測定範囲が広すぎます。 あなたのサービスはどこで時間を費やしていますか? プロファイラーを使用してこれを測定するか、さまざまなセクションの開始と終了をログに記録することができます。それさえできない場合は、Andrea Bertani の提案を使用してください - 他のセクションを削除してセクションを分離してください。

大まかな領域を特定したら、CPU 使用率の原因を突き止めるまで、さらに細かい測定を行うことができます。その時点でそれを修正する方法が明らかでない場合は、少なくとも、より具体的な質問に対する弾薬があります。

実際、この通常のトラブルシューティングをすべて既に行っている場合は、その秘密を教えてください.

于 2008-08-26T18:57:56.390 に答える