2009-08-18 7 views
5

Podczas tworzenia HttpWebRequest w ramach procedury składowanej CLR (zgodnie z kodem poniżej), pierwsze wywołanie po Sql Server jest (ponownie) rozpoczęte lub po danym (ale nieokreślonym) okresie czas oczekiwania na dość długi czas na wywołanie metody GetResponse().HttpWebRequest działa wolno po raz pierwszy w SQLCLR

Czy istnieje sposób rozwiązania tego problemu, który nie wiąże się z "włamaniem", takim jak uruchamianie zadania agenta serwera Sql co kilka minut, aby upewnić się, że pierwsze "wolne" wywołanie zostało wykonane przez agenta, a nie "prawdziwy" kod produkcyjny?

function SqlString MakeWebRequest(string address, string parameters, int connectTO) 
{ 
    SqlString returnData; 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString())); 
    request.Timeout = (int)connectTO; 
    request.Method = "GET"; 
    using (WebResponse response = request.GetResponse()) 
    { 
    using (Stream responseStream = response.GetResponseStream()) 
    { 
     using (StreamReader reader = new StreamReader(responseStream)) 
     { 
     SqlString responseFromServer = reader.ReadToEnd(); 
     returnData = responseFromServer; 
     } 
    } 
    } 
    response.Close(); 

    return returnData; 
} 

(obsługa błędów i drugi kod niekrytycznym jest usuwane Ben dla uproszczenia)


Patrz również this Sql Server forums thread.

+0

Jak długi jest czas oczekiwania na połączenie w pierwszej rozmowie z 2-krotnym czasem połączenia? Czy to połączenie z tym samym identyfikatorem URI jest zwykle? – BigBlondeViking

+0

Wierzę (z mojej góry), że "30 sekund, a połączenie jest wykonane na adres URL, który jest adresem IP, więc nie sądzę, że DNS byłby problem :( – Rob

+0

Czy uważasz, patrząc na Ruch HTTP z czymś takim jak WireShark? Lub wszystko z przewodu zostało wykluczone –

Odpowiedz

10

To było dla mnie problemem stosując HttpWebRequest w pierwszej kolejności. To ze względu na klasę szukającą proxy. Jeśli ustawisz wartość obiektu Proxy na null/Nothing, zostanie ona zsynchronizowana.

+0

To z pewnością wydaje się być przyczyną * większego * (dużo) dłuższego czasu trwania pierwszego połączenia. Ale wciąż pozostaje (być może) niewielka różnica. Jakieś pomysły dotyczące tego, co jeszcze może wywoływać wolniejsze wywołania (przy użyciu 'HttpWebRequest')? –

0

Zawsze występuje opóźnienie przy pierwszym ładowaniu przez SQLCLR niezbędnych złożeń. Tak powinno być nie tylko z funkcją MakeWebRRest, ale także z każdą funkcją .NET w SQLCLR.

+0

Niestety nie jest to problem tutaj, lub nie wydaje się, jak każda inna funkcja w naszym CLR Assembly może być wywołana i wykonana, ale po raz pierwszy nazywa się to blokuje na "request.GetResponse()" – Rob

0

HttpWebRequest jest częścią zestawu System.Net, który nie jest częścią supported libraries. Zalecam używanie biblioteki System.Web.Services zamiast wywoływania usług sieciowych z poziomu SQLCLR.

+0

Ponownie, nie problem. Używamy innych części System.Net bez żadnego problemu. "Obsługiwany" lub w inny sposób jest nieistotny w kontekście tego pytania. Plus, System.Web.Services służy do * tworzenia * usług internetowych, bez ładowania stron internetowych/wywoływania serwisów internetowych. – Rob

1

Nie jesteś pewien, ale czy opóźnienie jest wystarczająco długie, aby początkowe zapytania DNS mogły być przyczyną? (jak długo jest opóźnienie werset normalnej rozmowy?)

i/lub

Czy to URI do sieci wewnętrznej/lub innej sieci wewnętrznej?

Widziałem dziwne opóźnień sieciowych z użyciem profili balansu obciążenia wewnątrz sieci, która nie jest w porządku ustawień, firewalle, nośność-wyważarki i inne profile sieciowe może być „walka” początkowe połączenia ...

nie jestem wielkim facet sieci, ale może chcesz zobaczyć, jakie skojarzenie ma do powiedzenia na ten temat, jak również na serverfault.com ...

powodzenia

0

ja testowałem i mój pierwszy zimno Uruchom (po restarcie usługi SQL) był w 3 sekundy (nie 30 jak twój), wszystkie inne są w 0 sek.

Próbka Kod Użyłem zbudować DLL:

using System; 
using System.Data; 
using System.Net; 
using System.IO; 
using System.Data.SqlClient; 
using System.Data.SqlTypes; 
using Microsoft.SqlServer.Server; 

namespace MySQLCLR 
{ 
    public static class WebRequests 
    { 
     public static void MakeWebRequest(string address, string parameters, int connectTO) 
     { 
      string returnData; 
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(String.Concat(address.ToString(), "?", parameters.ToString())); 
      request.Timeout = (int)connectTO; 
      request.Method = "GET"; 
      using (WebResponse response = request.GetResponse()) 
      { 
       using (Stream responseStream = response.GetResponseStream()) 
       { 
        using (StreamReader reader = new StreamReader(responseStream)) 
        { 
         returnData = reader.ReadToEnd(); 
         reader.Close(); 
        } 
        responseStream.Close(); 
       } 
       response.Close(); 
      } 
      SqlDataRecord rec = new SqlDataRecord(new SqlMetaData[] { new SqlMetaData("response", SqlDbType.NVarChar, 10000000) }); 
      rec.SetValue(0, returnData); 
      SqlContext.Pipe.Send(rec); 
     } 
    } 
} 
+0

Właśnie potwierdziłem z moim kolegą, że opóźnienie wynosi około 15 sekund, a nie 30, które myślałem, że to było i dzieje się to po ponownym uruchomieniu serwera SQL lub określonym okresie nieaktywności, który musimy jeszcze zidentyfikować (tj. z dnia na dzień). – Rob

+0

Problem leży zatem gdzie indziej, po prostu nie mamy środowiska, w którym można by je odtworzyć. Czy uważasz, że 3s na zimny start jest nie do przyjęcia? –

4

Wygląda jak weryfikacja podpisu kodu. Przesyłane pliki systemowe MS są podpisane, a SQL weryfikuje podpisy w czasie ładowania. Wygląda na to, że lista odwołania certyfikatów wygasła, a mechanizm weryfikacji certyfikatu przekroczył czas pobierania nowej listy. Napisałem na blogu o tym problemie przed Fix slow application startup due to code sign validation, a problem jest również opisany w tym artykule w serwisie Technet: Certificate Revocation and Status Checking.

Rozwiązanie jest dość ezoteryczne i polega na edycji rejestru klucza: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config:

  • ChainUrlRetrievalTimeoutMilliseconds To jest każdy indywidualny limit czasu połączenia check CRL. Jeśli jest 0 lub nie występuje, używana jest domyślna wartość 15 sekund. Zmień ten limit czasu na rozsądną wartość, np. 200 milisekund.
  • ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds Jest to łączny limit czasu pobierania listy CRL. Jeśli ustawione na 0 lub nie występuje, używana jest wartość domyślna wynosząca 20 sekund. Zmień ten limit czasu na wartość zbliżoną do 500 milisekund.

Jest także bardziej specyficzne rozwiązanie dla Microsoft signed assemblies (to z dokumentacji Biztalk, ale odnosi się do dowolnego obciążenia montażowego):

ręcznie załadować Microsoft Certificate Odwołanie wymienia

Po uruchomieniu aplikacji .NET, .NET Framework podejmie próbę uzyskania pobrania listy CRL (Certificate Revocation) o (CRL) dla każdego podpisanego jako sembly. Jeśli Twój system nie ma bezpośredniego dostępu do Internetu lub nie jest dostępny , nie może uzyskać dostępu do domeny Microsoft.com o numerze , może to opóźnić uruchomienie BizTalk Server o . Aby uniknąć opóźnienia przy uruchamianiu aplikacji, użytkownik może ręcznie wykonać następujące kroki, aby ręcznie pobrać i zainstalować kod podpisujący listy cofania certyfikatów w systemie.

  1. pobrać najnowsze aktualizacje CRL z http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl i http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl.
  2. Przenieś pliki CodeSignPCA.crl i CodeSignPCA2.crl do izolowanego systemu .
  3. W wierszu polecenia wpisz następujące polecenie, aby korzystać z Certutil narzędzia do aktualizacji lokalnego magazynu certyfikatów z CRL pobranego w kroku 1: certutil -addstore CA c: \ CodeSignPCA.crl

Pliki listy CRL są regularnie aktualizowane, , dlatego należy rozważyć ponowne uruchomienie zadania pobierania i oraz instalowanie aktualizacji list CRL. Aby wyświetlić następny czas aktualizacji, kliknij dwukrotnie plik .crl i wyświetl wartość następnego pola Aktualizuj w polu .

+0

Oczywiście jest to dość niezwykłe, że wywołania serwisowe serwera nie mogą uzyskać dostępu do serwera CRL, więc mogę odejść, ale symptomy wyglądają podobnie jak sprawdzanie listy CRL. –

+0

Jest to bardzo przydatne wiedzieć. Mam problem z przekroczeniem limitu czasu CRL w innej formie (ładowanie kodu .NET C# obrazy TIFF wysyłają żądanie CRL, które przekroczyło limit czasu, ponieważ komputery nie są połączone z Internetem, co powoduje, że ładowanie obrazu zajmuje 30 sekund). Rejestru hack jest nieco podejrzany, ale ładowanie CRL ręcznie wydaje się rozsądnym rozwiązaniem. – Conceptdev

+0

@Craig: Tak, w zasadzie każde stworzenie w domenie może to zrobić i jest prawie niemożliwe do zdiagnozowania, chyba że o tym wiesz. Pierwsze trafienie na stronie internetowej ASP, najpierw wywołanie dll, aplikacja zawiesza się na 30 sekund przy obciążeniu, wszystkie objawy tego samego problemu. –