17

IIS 6.0 でホストされている WCF サービス (.NET Framework 3.5 に組み込まれている) を使用しています。

コードの流れは以下の通り

  1. クライアント (別の Web サービス) が WCF サービスを呼び出す
  2. WCF サービスはスレッドを呼び出してバックグラウンドで処理を行い、呼び出し先にすぐに応答します。
  3. すべての処理が完了すると、バックグラウンド スレッドがスレッドをコールバックします。クライアントは Web サービスであるため、この呼び出しは基本的に HTTPS 要求です。

しきい値を定義するために、WCF サービスの負荷テストを行っています。観察は次のとおりです。

1 分以内に WCF サービスに対して行われた 1024 の要求の約 3 回の反復が正常に通過します。各反復を完了するのにかかる時間は、約 25 ~ 30 分です。ただし、4 回目のイテレーションからバルク エラーが見られます。リクエストの約 50% は、以下の例外で失敗します。

Exception-Thread が中止されました。

スタックトレース

21_10_2016_09_30_52,9:30:52 AM,Information,Thread name- apSwTTbLTETfwT3y Stack trace in ProcessTestConversion method -    at System.Threading.WaitHandle.WaitOneNative(SafeHandle waitableSafeHandle, UInt32 millisecondsTimeout, Boolean hasThreadAffinity, Boolean exitContext)
   at System.Threading.WaitHandle.InternalWaitOne(SafeHandle waitableSafeHandle, Int64 millisecondsTimeout, Boolean hasThreadAffinity, Boolean exitContext)
   at System.Threading.WaitHandle.WaitOne(Int32 millisecondsTimeout, Boolean exitContext)
   at System.Net.LazyAsyncResult.WaitForCompletion(Boolean snap)
   at System.Net.Connection.SubmitRequest(HttpWebRequest request, Boolean forcedsubmit)
   at System.Net.ServicePoint.SubmitRequest(HttpWebRequest request, String connName)
   at System.Net.HttpWebRequest.SubmitRequest(ServicePoint servicePoint)
   at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
   at System.Net.HttpWebRequest.GetRequestStream()
   .
   .(My function calls stack trace)
   .
   .

この問題を解決しようとした変更は次のとおりです。

   <behavior>
    <serviceThrottling maxConcurrentCalls="2000"
                                 maxConcurrentInstances ="2400"
                                 maxConcurrentSessions ="400"/>
    </behavior>

web.config で

<system.web>
        <compilation debug="false" />
        <httpRuntime executionTimeout="1800"/>
    </system.web>

web.config で

  <system.net>
        <connectionManagement>
          <add address = "*" maxconnection = "100" />
        </connectionManagement>
      </system.net>

web.config で

ServicePointManager.DefaultConnectionLimit = 100; (Change in code)

StackOverflow で多くの人が提案しているように、App プールの IdleTimeout プロパティを 0 に設定しました。

ストリームが使用される場所はどこでも、すべての場所で処分しました。したがって、すべてのストリームが閉じられます。

誰がスレッドを中止しているのか、その理由を教えてもらえますか?また、スレッド中止の開始の原因を追跡する手段やツールはありますか?

4

2 に答える 2

5

私はこの問題に遭遇しましたが、クライアント クラスの不適切な使用が原因でした。

クライアント クラスがインスタンス化されたときに、リソースが解放されず、スループットが低下していました。非常に役に立たない例外「スレッドが中止されました」が発生します。これは、ジェネリックally がクライアント オブジェクトを作成し、コンストラクターと dispose メソッドを正しく実装するヘルパー クラスを作成することで解決されました。

一部の IIS 例外は、問題の実際の原因にはあまり役に立たないか、真実ではありませんが、問題を解決するために何が行われたかを理解するには、IIS ログを確認する必要がありました。具体的には「失敗したリクエスト トレース ルール

これが役に立てば幸いです。解決するのが頭痛の種だったあなたの不満を理解できます。

于 2016-10-31T15:40:39.150 に答える
2

私は以前に同じことに直面しました。解決策は、 Disposeメソッドを実装して、スコープが終了した後にリソース/クライアントを解放することでした。

型指定されたクライアントを使用するときにリソースを自動的にクリーンアップする C#usingステートメントが成功せず、スローされた例外が暗黙的な破棄によってマスクされ、実際の例外を消費し、タイムアウトやその他の例外などの他の例外がスローされるため、問題が存在します。

C# の "using" ステートメントにより、Dispose() が呼び出されます。これは、ネットワーク エラーが発生したときに例外をスローする可能性がある Close() と同じです。Dispose() の呼び出しは "using" ブロックの右中括弧で暗黙的に行われるため、この例外の発生源は、コードを書いている人もコードを読んでいる人も気付かない可能性があります。これは、アプリケーション エラーの潜在的な原因を表しています。( MSDNから)

次のようなリソースを解放する必要があります。

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

このようにして、例外の実際のソースを見つけるだけでなく、何らかの実行が発生したときにリソースを解放することもできます。

他の代替ソリューションは、次のように実装できますDispose

/// <summary>
/// Calculator Client
/// </summary>
public partial class CalculatorClient : IDisposable
{
    #region IDisposable implementation

    /// <summary>
    /// IDisposable.Dispose implementation, calls Dispose(true).
    /// </summary>
    void IDisposable.Dispose()
    {
        Dispose(true);
    }

    /// <summary>
    /// Dispose worker method. Handles graceful shutdown of the
    /// client even if it is an faulted state.
    /// </summary>
    /// <param name="disposing">Are we disposing (alternative
    /// is to be finalizing)</param>
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            try
            {
                if (State != CommunicationState.Faulted)
                {
                    Close();
                }
            }
            finally
            {
                if (State != CommunicationState.Closed)
                {
                    Abort();
                }
            }
        }
    }

    /// <summary>
    /// Finalizer.
    /// </summary>
    CalculatorClient()
    {
        Dispose(false);
    }

    #endregion
}

ソース:

Using ステートメントに関する問題の回避MSDN

WCF クライアントの使用と破棄

于 2016-11-01T14:23:18.163 に答える