2009-08-18 27 views
5

Al realizar una HttpWebRequest dentro de un procedimiento almacenado CLR (según el código siguiente), la primera invocación después del servidor Sql se reinicia o después de un período determinado (pero indeterminado) de el tiempo de espera durante bastante tiempo en la llamada al método GetResponse().HttpWebRequest se ejecuta lentamente por primera vez dentro de SQLCLR

¿Hay alguna manera de resolver esto que no involucre un "hackeo" como tener un trabajo del Agente de servidor Sql ejecutándose cada pocos minutos para intentar que la primera llamada "lenta" sea realizada por el agente y no código de producción "real"?

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

(manejo de errores y otro código no crítico tiene ben eliminado por razones de brevedad)


Consulte también this Sql Server forums thread.

+0

¿Cuánto tiempo dura el tiempo de espera de la primera llamada frente al segundo + tiempo de llamadas? ¿Es esta llamada a la misma URI por lo general? – BigBlondeViking

+0

Creo (fuera de mi cabeza) es '30 segundos, y la llamada se realiza a una URL que es una dirección IP, por lo que no creo que el DNS sea un problema :( – Rob

+0

¿Consideró mirar el Tráfico HTTP con algo así como WireShark o se ha descartado todo en el cable. –

Respuesta

10

Este fue un problema para mí usando HttpWebRequest al principio. Es debido a que la clase busca un proxy para usar. Si configura el valor Proxy del objeto en null/Nothing, se cerrará automáticamente.

+0

Esto definitivamente parece haber sido la causa del * volumen de * la duración (mucho) más larga de la llamada inicial. Pero todavía hay (tal vez) una pequeña diferencia restante. ¿Alguna idea sobre qué más podría estar haciendo que las llamadas iniciales sean más lentas (cuando se usa 'HttpWebRequest')? –

0

Siempre hay un retraso la primera vez que SQLCLR carga los ensamblajes necesarios. Ese debería ser el caso no solo para su función MakeWebRequest, sino también para cualquier función .NET en el SQLCLR.

+0

Desafortunadamente este no es el problema aquí, o no parece ser así, ya que cualquier otra función en nuestro conjunto CLR se puede llamar y ejecutar, pero la primera vez que se llama bloquea en "request.GetResponse()" – Rob

0

HttpWebRequest es parte del ensamblado System.Net, que no forma parte del supported libraries. Recomiendo usar la biblioteca System.Web.Services en su lugar para realizar llamadas al servicio web desde el interior del SQLCLR.

+0

Una vez más, no es el problema. Estamos usando otras partes de System.Net sin ningún tipo de problema. "Compatible" o de otro modo es irrelevante en el contexto de esta pregunta. Además, System.Web.Services es para * crear * servicios web, no cargar páginas web/llamar a servicios web. – Rob

1

No estoy seguro, pero si la demora es lo suficientemente larga como para que las búsquedas DNS iniciales sean las culpables? (cuánto tiempo es el retraso verso de una llamada normal?)

y/o

Es esta URI interna a la Red/o una red interna diferente?

he visto algunos retrasos de redes extrañas desde el uso de perfiles de equilibrio de carga dentro de una red que no es correcta la configuración, los firewalls, balanceadores de carga, y otros perfiles de red podría ser "la lucha contra" las conexiones iniciales ...

no soy un gran tipo de redes, pero puede que desee ver lo que una SA tiene que decir acerca de esto en serverfault.com así ...

buena suerte

0

he probado y mi primer fría ejecutar (después del reinicio del servicio de SQL) fue en 3 segundos (no 30 como el suyo), todos los demás están en 0 segundos.

El ejemplo de código que he utilizado para construir un archivo 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

Acabo de confirmar con mi colega que la demora es de aproximadamente 15 segundos, no los 30 que pensé que era y esto ocurre después del reinicio del Servidor Sql o de un cierto período de inactividad que todavía tenemos que identificar (es decir, durante la noche) – Rob

+0

Entonces, el problema reside en otro lugar, simplemente no tenemos un entorno para reproducirlo. ¿Crees que 3s para el arranque en frío es inaceptable? –

4

Me parece que la verificación de firma de código. Los dlls del sistema MS enviados están todos firmados y SQL verifica las firmas en el momento de la carga. Aparentemente, la lista de revocación de certificados ha expirado y el motor de verificación de certificados agota el tiempo de recuperación de una nueva lista. He escrito sobre este problema antes de Fix slow application startup due to code sign validation y el problema también se describe en este artículo de Technet: Certificate Revocation and Status Checking.

La solución es bastante arcano e implica la edición del registro de la clave: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config:

  • ChainUrlRetrievalTimeoutMilliseconds Esto es cada tiempo de espera de verificación CRL llamada individual. Si es 0 o no está presente, se usa el valor predeterminado de 15 segundos. Cambie este tiempo de espera a un valor razonable como 200 milisegundos.
  • ChainRevAccumulativeUrlRetrievalTimeoutMilliseconds Este es el tiempo de espera de recuperación de CRL agregado. Si se establece en 0 o no está presente, se usa el valor predeterminado de 20 segundos. Cambie este tiempo de espera a un valor como 500 milisegundos.

También hay una solución más específica para Microsoft signed assemblies (esto es de la documentación de BizTalk, pero se aplica a cualquier carga de montaje):

cargar manualmente Microsoft Certificate revocación enumera

Al iniciar una aplicación .NET, el .NET Framework intentará descargar la lista de revocación de certificados (CRL) para cualquier firma como sembly Si su sistema no tiene acceso directo a o está restringido para acceder al dominio de Microsoft.com, esto puede retrasar el inicio de BizTalk Server. Para evitar este retraso en el inicio de la aplicación, puede utilizar manualmente los siguientes pasos para descargar e instalar manualmente el código firmando las listas de revocación de certificados en su sistema.

  1. descargar las últimas actualizaciones de CRL http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl y http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl.
  2. Mueva los archivos CodeSignPCA.crl y CodeSignPCA2.crl al sistema aislado .
  3. Desde un símbolo del sistema, escriba el siguiente comando para utilizar el certutil utilidad para actualizar el almacén de certificados local con la CRL descargado en el paso 1: certutil -addstore CA c: \ CodeSignPCA.crl

Los archivos CRL se actualizan regularmente, , por lo que debe considerar establecer una tarea recurrente de descarga y instalar las actualizaciones CRL. Para ver la próxima vez que actualice, haga doble clic en el archivo .crl y vea el valor del campo Próxima actualización.

+0

Por supuesto, es un poco inusual que el servidor que realiza llamadas al servicio web no pueda acceder al servidor CRL, por lo que es posible que no pueda acceder, pero los síntomas se parecen mucho a la verificación de CRL. –

+0

Eso es muy útil para saber. He pulsado el problema de tiempo de espera de CRL de otra forma (el código .NET C# cargando imágenes TIFF hace que una solicitud CRL exista un tiempo de espera porque las PC no están conectadas a Internet, lo que hace que la carga de imagen tome 30 segundos). El hack de registro es un poco dudoso, pero cargar la CRL manualmente parece ser una solución sensata. – Conceptdev

+0

@Craig: Sí, básicamente cualquier creación de dominio de aplicación puede golpear esto, y es casi imposible de diagnosticar a menos que sepa al respecto. Primer golpe en un sitio web ASP, primero llame a un dll, la aplicación se congela durante 30 segundos a la carga, todos los síntomas del mismo problema. –

Cuestiones relacionadas