2009-08-18 3 views
5

Wenn Sie eine HttpWebRequest innerhalb einer gespeicherten CLR-Prozedur (gemäß dem folgenden Code), der erste Aufruf nach dem Sql Server ist (neu) gestartet oder nach einem bestimmten (aber unbestimmten) Zeitraum von Die Zeit wartet beim GetResponse() -Methodenaufruf ziemlich lange.HttpWebRequest läuft langsam zuerst innerhalb SQLCLR

Gibt es eine Möglichkeit, dies zu beheben, die nicht einen "Hack" wie einen Sql Server Agent Job alle paar Minuten ausgeführt wird, um sicherzustellen, dass der erste "langsame" Anruf vom Agenten und nicht gemacht wird "echter" Produktionscode?

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; 
} 

(Fehlerbehandlung und anderen nicht-kritischen Code hat ben der Kürze entfernt)


Siehe auch this Sql Server forums thread.

+0

Wie lange ist dieser erste Anruf Wartezeit gegen 2. + Anruf mal? Ist dieser Aufruf an dieselbe URI normalerweise? – BigBlondeViking

+0

Ich glaube (von Kopf bis Kopf) ist es 30 Sekunden, und der Anruf wird an eine URL, die eine IP-Adresse ist gemacht, so glaube ich nicht, dass DNS ein Problem wäre :( – Rob

+0

Haben Sie darüber nachgedacht, die HTTP-Verkehr mit etwas wie WireShark? Oder ist alles auf dem Draht ausgeschlossen worden? –

Antwort

10

Das war ein Problem für mich HttpWebRequest zunächst mit. Es ist wegen der Klasse, die nach einem zu verwendenden Proxy sucht. Wenn Sie den Wert Proxy des Objekts auf null/Nothing festlegen, wird es direkt zip.

+0

Dies scheint eindeutig der Grund für die * große * Dauer des ersten Anrufs gewesen zu sein. Aber es bleibt (vielleicht) noch ein kleiner Unterschied. Irgendwelche Ideen darüber, was die ersten Aufrufe langsamer machen könnte (wenn 'HttpWebRequest' verwendet wird)? –

0

Es gibt immer eine Verzögerung, wenn SQLCLR zum ersten Mal die erforderlichen Baugruppen lädt. Das sollte nicht nur für Ihre Funktion MakeWebRequest der Fall sein, sondern auch für eine beliebige .NET-Funktion in der SQLCLR.

+0

Leider ist dies nicht das Problem oder scheint es nicht zu sein, da jede andere Funktion in unserer CLR-Assembly aufgerufen und ausgeführt werden kann, aber beim ersten Aufruf dieses Blocks blockiert sie auf "request.GetResponse()" – Rob

0

HttpWebRequest ist Teil der System.Net-Baugruppe, die nicht Teil der supported libraries ist. Ich würde empfehlen, stattdessen die Bibliothek System.Web.Services zu verwenden, um Webdienstaufrufe von innerhalb des SQLCLR auszuführen.

+0

Noch einmal, nicht das Problem. Wir verwenden andere Teile von System.Net ohne irgendein Problem. "Unterstützt" oder anders ist im Zusammenhang mit dieser Frage irrelevant. Plus, System.Web.Services ist für das Erstellen * von Webservices, das Laden von Webseiten/das Anrufen von Webdiensten. – Rob

1

Nicht sicher, aber wenn die Verzögerung lange genug, dass erste DNS-Lookups der Schuldige sein könnte? (wie lange ist die Verzögerung Vers eines normalen Anruf?)

und/oder

Ist das URI intern im Netzwerk/oder ein anderes internes Netzwerk?

Ich habe einige seltsame Netzwerkverzögerungen verwenden, Lastausgleich Profile in einem Netzwerk gesehen, die nicht Setup richtig ist, die Firewalls, Load-Balancern und andere Netzwerkprofile könnten „kämpfen“ die ersten Verbindungen werden ...

ich bin kein großer Networking Kerl, aber Sie könnten sehen wollen, was ein SA dazu auf serverfault.com auch ...

viel Glück

0

ich getestet habe zu sagen hat, und mein erstes kalt run (nach dem Neustart des SQL-Dienstes) war in 3 Sekunden (nicht 30 wie deine), alle anderen sind in 0 Sekunden.

Das Codebeispiel die ich verwendet habe eine DLL zu erstellen:

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

Ich habe gerade mit meinem Kollegen bestätigt, dass die Verzögerung ungefähr 15 Sekunden beträgt, nicht die 30, die ich dachte und dies geschieht nach dem Sql Server Neustart oder einer bestimmten Inaktivitätsperiode, die wir noch identifizieren müssen (zB über Nacht) – Rob

+0

Also liegt das Problem woanders, wir haben einfach keine Umgebung um es zu reproduzieren. Denkst du 3s für Kaltstart ist inakzeptabel? –

4

Sieht für mich wie Code Signaturprüfung. Die von MS ausgelieferten System-DLLs sind alle signiert und SQL überprüft die Signaturen zum Zeitpunkt des Ladens. Anscheinend ist die Zertifikatswiderrufsliste abgelaufen und die Zertifikatsüberprüfungs-Engine gibt eine neue Liste aus. Ich habe über dieses Problem vor gebloggt und das Problem wird auch in diesem Technet-Artikel beschrieben: Certificate Revocation and Status Checking.

Die Lösung ist ziemlich obskur und beinhaltet zum Bearbeiten der Registrierung des Schlüssels: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config:

  • ChainUrlRetrievalTimeoutMilliseconds Dies ist jede einzelne CRL-Prüfung Aufruf Timeout. Wenn 0 oder nicht vorhanden ist, wird der Standardwert von 15 Sekunden verwendet. Ändern Sie diese Zeitüberschreitung in einen angemessenen Wert wie 200 Millisekunden.
  • ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds Dies ist das kumulierte CRL-Abruftimeout. Bei 0 oder nicht vorhanden wird der Standardwert von 20 Sekunden verwendet. Ändern Sie dieses Zeitlimit in einen Wert wie 500 Millisekunden.

Es gibt auch eine spezifische Lösung für Microsoft signed assemblies (dies aus der Biztalk Dokumentation, sondern gilt für alle Montagelast):

manuell laden Microsoft Certificate Sperrlisten

Wenn Sie eine .NET-Anwendung starten, wird das .NET Framework versuchen, die Zertifikatsperrliste (CRL) für alle signierten As herunterzuladen Versammlung. Wenn Ihr System keinen direkten Zugriff auf das Internet hat oder Zugriff auf die Domäne Microsoft.com eingeschränkt ist, kann dies den Start von BizTalk Server verzögern. Um diese Verzögerung beim Start der Anwendung zu vermeiden, können Sie die folgenden Schritte zu manuell herunterladen und installieren Sie den Code Signieren von Zertifikatssperrlisten auf Ihrem System.

  1. Laden Sie die neuesten Updates von CRL http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl und http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl.
  2. Verschieben Sie die Dateien CodeSignPCA.crl und CodeSignPCA2.crl zum isolierten System .
  3. Von einer Eingabeaufforderung geben Sie den folgenden Befehl, um die certutil Dienstprogramm zu verwenden, um die lokalen Zertifikatspeicher mit den CRL in Schritt 1 heruntergeladen zu aktualisieren: certutil -addstore CA c: \ CodeSignPCA.crl

Die CRL-Dateien werden regelmäßig aktualisiert, , so dass Sie eine wiederkehrende Aufgabe des Herunterladens und Installation der CRL-Updates in Betracht ziehen sollten. Um die nächste Aktualisierungszeit anzuzeigen, doppelklicken Sie auf die Datei .crl und zeigen Sie den Wert des Feldes Nächste Aktualisierung an.

+0

Natürlich ist es etwas ungewöhnlich, dass der Server, der Web-Service-Anrufe tätigt, den CRL-Server nicht annehmen kann, so dass ich mich vielleicht abmelden kann, aber die Symptome ähneln der CRL-Prüfung. –

+0

Das ist sehr nützlich zu wissen. Ich habe das CRL Timeout-Problem in einer anderen Form (.NET C# Code-Laden TIFF-Bilder fordert eine CRL-Anfrage, dass Time-Out, weil die PCs nicht mit dem Internet verbunden sind, verursacht Bild laden dauert 30 Sekunden). Der Registrierungs-Hack ist ein bisschen zweifelhaft, aber das manuelle Laden der CRL scheint eine vernünftige Lösung zu sein. – Conceptdev

+0

@Craig: Ja, im Grunde kann jede AppDomain-Erstellung dies treffen, und ist fast unmöglich zu diagnostizieren, wenn Sie es nicht wissen. Erstes Drücken auf eine ASP-Website, zuerst Aufruf in eine DLL, App friert für 30 Sekunden beim Laden, alle Symptome des gleichen Problems. –