Problemy z wydajnością podczas nawiązywania połączeń z usługami internetowymi z aplikacji ASP.NET

Ten artykuł zawiera pomoc w rozwiązywaniu problemów z wydajnością występujących podczas nawiązywania połączeń z usługami internetowymi z aplikacji microsoft ASP.NET.

Oryginalna wersja produktu: ASP.NET
Oryginalny numer KB: 821268

Symptomy

Podczas wykonywania wywołań do usług internetowych z aplikacji ASP.NET mogą wystąpić rywalizacje, niska wydajność i zakleszczenia. Klienci mogą zgłaszać, że żądania przestają odpowiadać lub wykonywanie żądań zajmuje dużo czasu. Jeśli podejrzewa się zakleszczenie, proces roboczy może zostać poddany recyklingowi.

Podczas wykonywania wywołania metody może zostać wyświetlony następujący komunikat o błędzie wyjątku HttpWebRequest.GetResponse :

"System.InvalidOperationException: W obiekcie ThreadPool nie było wystarczającej liczby wolnych wątków, aby ukończyć operację".

W przeglądarce może również zostać wyświetlony następujący komunikat o błędzie wyjątku:

"HttpException (0x80004005): upłynął limit czasu żądania".

Uwaga

Ten artykuł dotyczy również aplikacji, które bezpośrednio składają HttpWebRequest żądania.

Przyczyna

Ten problem może wystąpić, ponieważ ASP.NET ogranicza liczbę wątków procesów roboczych i wątków portów uzupełniania, których wywołanie może użyć do wykonywania żądań.

Zazwyczaj wywołanie usługi internetowej używa jednego wątku roboczego do wykonania kodu wysyłającego żądanie i jednego wątku portu ukończenia w celu odebrania wywołania zwrotnego z usługi internetowej. Jeśli jednak żądanie zostanie przekierowane lub wymaga uwierzytelnienia, wywołanie może używać aż dwóch wątków procesu roboczego i dwóch wątków portu ukończenia. W związku z tym można wyczerpyć zarządzane ThreadPool , gdy w tym samym czasie wystąpi wiele wywołań usługi internetowej.

Załóżmy na przykład, że ThreadPool obiekt jest ograniczony do 10 wątków roboczych i że wszystkie 10 wątków roboczych aktualnie wykonuje kod, który oczekuje na wykonanie wywołania zwrotnego. Wywołanie zwrotne nigdy nie może zostać wykonane, ponieważ wszystkie elementy robocze, które są umieszczane w kolejce do obiektu ThreadPool , są blokowane, dopóki wątek nie stanie się dostępny.

Innym potencjalnym źródłem rywalizacji jest maxconnection parametr używany przez System.Net przestrzeń nazw do ograniczenia liczby połączeń. Ogólnie rzecz biorąc, ten limit działa zgodnie z oczekiwaniami. Jeśli jednak wiele aplikacji spróbuje jednocześnie wysłać wiele żądań do pojedynczego adresu IP, wątki mogą czekać na dostępne połączenie.

Rozwiązanie

Aby rozwiązać te problemy, możesz dostroić następujące parametry w pliku Machine.config , aby najlepiej dopasować się do twojej sytuacji:

  • maxWorkerThreads
  • minWorkerThreads
  • maxIoThreads
  • minFreeThreads
  • minLocalRequestFreeThreads
  • maxconnection
  • executionTimeout

Aby pomyślnie rozwiązać te problemy, wykonaj następujące czynności:

  • Ogranicz liczbę żądań ASP.NET, które mogą być wykonywane w tym samym czasie, do około 12 na procesor CPU.
  • Zezwalaj wywołaniom zwrotnym usługi internetowej na swobodne używanie wątków w pliku ThreadPool.
  • Wybierz odpowiednią wartość parametru maxconnections . Oparcie wyboru na liczbie używanych adresów IP i domen aplikacji.

Uwaga

Zalecenie ograniczenia liczby żądań ASP.NET do 12 na procesor CPU jest nieco dowolne. Jednak ten limit okazał się dobrze w przypadku większości aplikacji.

MaxWorkerThreads i maxIoThreads

ASP.NET używa następujących dwóch ustawień konfiguracji, aby ograniczyć maksymalną liczbę wątków roboczych i wątków uzupełniania, które są używane:

<processModel maxWorkerThreads="20" maxIoThreads="20">

Parametr maxWorkerThreads i maxIoThreads parametr są niejawnie mnożone przez liczbę procesorów CPU. Jeśli na przykład masz dwa procesory, maksymalna liczba wątków roboczych wynosi 2 * maxWorkerThreads.

MinFreeThreads i minLocalRequestFreeThreads

ASP.NET zawiera również następujące ustawienia konfiguracji, które określają, ile wątków procesów roboczych i wątków portów uzupełniania musi być dostępnych do uruchomienia żądania zdalnego lub żądania lokalnego:

<httpRuntime minFreeThreads="8" minLocalRequestFreeThreads="8">

Jeśli nie ma wystarczającej liczby dostępnych wątków, żądanie jest umieszczane w kolejce, dopóki nie będzie można utworzyć żądania przez wystarczającą liczbę wątków. Dlatego ASP.NET nie będzie wykonywać więcej niż następująca liczba żądań w tym samym czasie:

(maxWorkerThreads * liczba procesorów CPU) - minFreeThreads

Uwaga

Parametr minFreeThreads i minLocalRequestFreeThreads parametr nie są niejawnie pomnożone przez liczbę procesorów CPU.

MinWorkerThreads

ASP.NET zawiera również następujące ustawienie konfiguracji, które określa, ile wątków roboczych może zostać natychmiast udostępnionych do obsługi żądania zdalnego.

<processModel minWorkerThreads="1">

Wątki kontrolowane przez to ustawienie można tworzyć z dużo szybszym szybkością niż wątki robocze utworzone na podstawie domyślnych możliwości dostrajania wątków w środowisku uruchomieniowym języka wspólnego (CLR).

To ustawienie umożliwia ASP.NET do obsługi żądań, które mogą nagle wypełniać kolejkę żądań ASP.NET z powodu spowolnienia na serwerze zaplecza, nagłego wzrostu liczby żądań z końca klienta lub czegoś podobnego, co spowodowałoby nagły wzrost liczby żądań w kolejce.

Wartość domyślna parametru minWorkerThreads to 1. Zalecamy ustawienie wartości parametru minWorkerThreads na następującą wartość:

minWorkerThreads = maxWorkerThreads / 2

Domyślnie minWorkerThreads parametr nie jest obecny w pliku Web.config lub pliku Machine.config . To ustawienie jest niejawnie mnożone przez liczbę procesorów CPU.

Maxconnection

Parametr maxconnection określa, ile połączeń można nawiązać z określonym adresem IP. Parametr jest wyświetlany w następujący sposób:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://65.53.32.230" maxconnection="12">
</connectionManagement>

Jeśli kod aplikacji odwołuje się do aplikacji według nazwy hosta zamiast adresu IP, parametr powinien wyglądać następująco:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname" maxconnection="12">
</connectionManagement>

Na koniec, jeśli aplikacja jest hostowana na porcie innym niż 80, parametr musi zawierać niestandardowy port w adresie URL, podobnie jak poniżej:

<connectionManagement>
    <add address="*" maxconnection="2">
    <add address="http://hostname:8080" maxconnection="12">
</connectionManagement>

Ustawienia parametrów omówionych wcześniej w tym artykule są na poziomie procesu. Jednak ustawienie parametru maxconnection ma zastosowanie do poziomu AppDomain. Domyślnie, ponieważ to ustawienie dotyczy poziomu AppDomain, można utworzyć maksymalnie dwa połączenia z określonym adresem IP z każdej domeny aplikacji w procesie.

ExecutionTimeout

ASP.NET używa następującego ustawienia konfiguracji, aby ograniczyć czas wykonywania żądania:

<httpRuntime executionTimeout="90"/>

Ten limit można również ustawić przy użyciu Server.ScriptTimeout właściwości .

Uwaga

Jeśli zwiększysz wartość parametru executionTimeout , może być również konieczne zmodyfikowanie ustawienia parametru processModelresponseDeadlockInterval .

Zalecenia

Ustawienia zalecane w tej sekcji mogą nie działać dla wszystkich aplikacji. Jednak poniższe dodatkowe informacje mogą pomóc w dokonaniu odpowiednich korekt.

Jeśli wykonujesz jedno wywołanie usługi internetowej do pojedynczego adresu IP z każdej strony ASPX, firma Microsoft zaleca użycie następujących ustawień konfiguracji:

  • Ustaw wartości parametru maxWorkerThreads i parametru maxIoThreads na 100.
  • Ustaw wartość parametru maxconnection na 12*N (gdzie N to liczba procesorów CPU).
  • Ustaw wartości parametru minFreeThreads na 88*N , a minLocalRequestFreeThreads parametr na 76*N.
  • Ustaw wartość minWorkerThreadsna 50. Pamiętaj, minWorkerThreads że domyślnie nie znajduje się w pliku konfiguracji. Musisz go dodać.

Niektóre z tych zaleceń obejmują prostą formułę, która obejmuje liczbę procesorów CPU na serwerze. Zmienna reprezentująca liczbę procesorów CPU w formułach to N.

W przypadku tych ustawień, jeśli włączono hiperwątkowość, należy użyć liczby procesorów logicznych zamiast liczby fizycznych procesorów CPU. Jeśli na przykład masz serwer z czterema procesorami z włączoną funkcją hiperwątkowości, wartość N w formułach będzie wynosić 8 zamiast 4.

Uwaga

W przypadku korzystania z tej konfiguracji można wykonać maksymalnie 12 żądań ASP.NET na procesor CPU w tym samym czasie, ponieważ 100-88=12. W związku z tym co najmniej 88*N wątków roboczych i 88*N wątków portów uzupełniania są dostępne do innych zastosowań (takich jak wywołania zwrotne usługi internetowej).

Na przykład masz serwer z czterema procesorami i włączoną funkcją hyperthreading. Na podstawie tych formuł należy użyć następujących wartości dla ustawień konfiguracji wymienionych w tym artykule.

<system.web>
    <processModel maxWorkerThreads="100" maxIoThreads="100" minWorkerThreads="50"/>
    <httpRuntime minFreeThreads="704" minLocalRequestFreeThreads="608"/>
</system.web>
<system.net>
    <connectionManagement>
        <add address="[ProvideIPHere]" maxconnection="96"/>
    </connectionManagement>
</system.net>

Ponadto w przypadku korzystania z tej konfiguracji dla każdego obiektu AppDomain jest dostępnych 12 połączeń na procesor CPU na adres IP. W związku z tym w następującym scenariuszu bardzo mała rywalizacja występuje, gdy żądania oczekują na połączenia i ThreadPool nie są wyczerpane:

  • Sieć Web hostuje tylko jedną aplikację (AppDomain).
  • Każde żądanie dotyczące strony ASPX powoduje wysłanie jednego żądania usługi internetowej.
  • Wszystkie żądania mają ten sam adres IP.

Jednak w przypadku korzystania z tej konfiguracji scenariusze obejmujące jedną z poniższych opcji prawdopodobnie będą używać zbyt wielu połączeń:

  • Żądania są wysyłane do wielu adresów IP.
  • Żądania są przekierowywane (kod stanu 302).
  • Żądania wymagają uwierzytelniania.
  • Żądania są wykonywane z wielu domen aplikacji.

W tych scenariuszach dobrym pomysłem jest użycie niższej wartości parametru maxconnection i wyższych wartości parametru minFreeThreads i parametru minLocalRequestFreeThreads .

Więcej informacji

Aby uzyskać więcej informacji, zobacz Zwiększanie wydajności ASP.NET.

Jeśli występują słabe wyniki i rywalizacja o usługi IIS wraz z ASP.NET, przejdź do następujących blogów firmy Microsoft: