代码之家  ›  专栏  ›  技术社区  ›  Rob

httpwebrequest首次在sqlcr中运行缓慢

  •  5
  • Rob  · 技术社区  · 17 年前

    在clr存储过程中发出httpwebrequest时(根据下面的代码),SQL Server启动后或给定(但不确定)一段时间后的第一次调用等待getResponse()方法调用相当长的时间。

    是否有任何方法可以解决这一问题,而不涉及“黑客”,例如每隔几分钟运行一个SQL Server代理作业,以尝试确保第一个“慢速”调用是由代理发出的,而不是“真正的”生产代码?

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

    (为简洁起见,已删除错误处理和其他非关键代码)


    也见 this Sql Server forums thread .

    6 回复  |  直到 9 年前
        1
  •  10
  •   Kenny Evitt    9 年前

    这对我来说是个问题 HttpWebRequest 一开始。这是因为类正在寻找要使用的代理。如果设置对象的 Proxy 价值到 null / Nothing ,它会快速前进。

        2
  •  4
  •   Remus Rusanu    16 年前

    在我看来像代码签名验证。MS附带的系统DLL都已签名,SQL在加载时验证签名。显然,证书吊销列表已过期,证书验证引擎在检索新列表时超时。我以前写过关于这个问题的博客 Fix slow application startup due to code sign validation 本Technet文章还描述了该问题: Certificate Revocation and Status Checking .

    解决方案相当神秘,涉及注册表项的编辑: HKLM\SOFTWARE\Microsoft\Cryptography\OID\EncodingType 0\CertDllCreateCertificateChainEngine\Config :

    • 链URLRetrievalTimeout毫秒 这是每个单独的CRL检查调用超时。如果为0或不存在,则使用默认值15秒。将此超时值更改为200毫秒之类的合理值。
    • 链更新累计时间(毫秒) 这是聚合CRL检索超时。如果设置为0或不存在,则使用默认值20秒。将此超时值更改为500毫秒。

    还有一个更具体的解决方案 Microsoft signed assemblies (这来自于Biztalk文档,但适用于任何程序集加载):

    手动加载Microsoft证书 吊销列表

    启动.NET应用程序时, .NET框架将尝试 下载证书吊销 任何已签名程序集的列表(crl)。如果 您的系统没有直接 访问互联网,或 限制访问 Microsoft.com域,这可能会延迟 启动Biztalk Server。避免 应用程序启动时的延迟,您 可以使用以下步骤 手动下载并安装代码 签名证书吊销列表 在你的系统上。

    1. 从下载最新的CRL更新 http://crl.microsoft.com/pki/crl/products/CodeSignPCA.crl http://crl.microsoft.com/pki/crl/products/CodeSignPCA2.crl .
    2. 将codesignpca.crl和codesignpca2.crl文件移动到独立的 系统。
    3. 在命令提示下,输入以下命令以使用certutil 用于更新本地 使用CRL的证书存储 在步骤1中下载: certutil addstore ca c:\codesignpca.crl

    定期更新CRL文件, 所以你应该考虑设置一个 下载和 正在安装CRL更新。查看 下次更新时,双击 .crl文件并查看 下一个更新字段。

        3
  •  1
  •   BigBlondeViking    17 年前

    不确定,但是如果延迟足够长,初始DNS查找可能是罪魁祸首? (延迟句是一个正常呼叫吗?)

    和/或

    此URI是网络内部的还是其他内部网络?

    我已经看到一些奇怪的网络延迟,因为在一个设置不正确的网络中使用负载平衡配置文件,防火墙、负载均衡器和其他网络配置文件可能会“对抗”初始连接…

    我不是一个很好的网络人,但你可能想看看SA在serverfault.com上对此有何评论…

    祝你好运

        4
  •  0
  •   Nestor    17 年前

    第一次SQLCLR加载必要的程序集时总是有延迟。 这不仅适用于函数makewebrequest,也适用于sqlcr中的任何.NET函数。

        5
  •  0
  •   Nestor    17 年前

    httpwebrequest是System.NET程序集的一部分,它不是 supported libraries . 我建议使用library system.web.services,而不是从sqlcr内部进行Web服务调用。

        6
  •  0
  •   Viktor Jevdokimov    17 年前

    我已经测试过了,我的第一次冷运行(在SQL服务重新启动之后)是在3秒钟内(而不是像您的30秒钟),所有其他的都在0秒钟内。

    我用来构建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);
            }
        }
    }
    
    推荐文章