【问题标题】:SqlConnection Doesn't Honor Timeout for IP Address Data Sources (.NET Core 2.2)SqlConnection 不支持 IP 地址数据源的超时 (.NET Core 2.2)
【发布时间】:2019-07-17 23:01:31
【问题描述】:

在我的应用程序中,我已将连接字符串的连接超时属性设置为 10 秒。我已经通过在调用 Open 之前检查 SqlConnection 对象上的 ConnectionTimeout 属性来验证这一点。但是,当我尝试打开与无法访问的服务器的连接时,大约需要一分钟才能引发异常,而不是 10 秒。

具体错误是:

System.Data.SqlClient.dll 中出现“System.Data.SqlClient.SqlException”类型的异常,但未在用户代码中处理:“建立与 SQL 的连接时发生与网络相关或特定于实例的错误服务器。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。 (提供者:命名管道提供者,错误:40 - 无法打开与 SQL Server 的连接)

在我的情况下,目标服务器只是关闭了。使用 SQL Server Management Studio 尝试连接到同一服务器时,连接失败同样需要大约一分钟时间。

更新

我创建了一个 C# 控制台应用程序进行测试,并将超时值设置为 3 秒。如果我使用 IP 地址,无论连接超时有多低,我都会在 47 秒左右超时。如果我使用任意字符串,那么我得到的超时大致相当于我指定的超时。所以这个问题与使用 IPV4 地址而不是域名有关。这是测试应用程序:

using System;
using System.Data.SqlClient;
using System.Diagnostics;

namespace test
{
  class Program
  {
    static void Main(string[] args)
    {
      Console.WriteLine("Hi Mom, I'm on the internet!");

      string conn_str = 
      "Data Source=<Some Address>;" + 
      "Initial Catalog=BLAHBLA;" + 
      "User ID=HOOTENANY;" + 
      "Password=password;" + 
      "Connect Timeout=3";

      using (SqlConnection conn = new SqlConnection(conn_str)) {
        Console.WriteLine(conn.ConnectionTimeout);
        Stopwatch stopWatch = Stopwatch.StartNew();
        try {
          conn.Open();
        }
        catch (Exception ex) {
          Console.WriteLine("Time till error: " + stopWatch.Elapsed.Seconds.ToString() + " seconds.");
        }
      }
    }
  }
}

【问题讨论】:

  • 我知道您说您对此很确定,但许多应用程序确实依赖于此。您能否分享一个演示此行为的简单代码示例,我无法直接使用 SqlConnection 重现您的问题,但我发现这可能发生在配置错误的 EF 实现中。
  • 并添加 nslookup 的输出作为主机名。需要查看是否有多个IP。
  • @DavidBrowne-Microsoft,不是多个 IP,因为问题与直接使用 IP 有关。
  • 哇! @DavidBrowne-Microsoft 如果我使用 IP4 地址作为数据源,我可以准确地重现该问题!除非超时 5 秒或更长,否则总是 21 秒

标签: sql-server .net-core connection-timeout


【解决方案1】:

这不是答案,但我想分享我用来证明 Ian 发现的这个问题的代码。

  • 我已在 v2.0、2.1 和 2.2.301 中验证了此行为

我不想编辑 OP 帖子,因为它已经足够好,但我确实想促进在这方面的更多实验,以便我们可以解决这个问题 :)

以下代码表明,第一次尝试连接到解析为主机的 IP 地址将在 47 秒后可靠地失败,但在同一 IP 上立即重试始终会在 21 秒后失败。

有趣的是,对于我的子网中未解析为主机的 IP,初始故障时间始终为 52 秒,然后又下降到 21 秒。

  • 我对此的解释是,部分延迟是由于解析(存在的主机约为 26 秒,同一子网上未解析的 IP 约为 31 秒。),并且一旦 IP 解析可以从缓存中访问主机,我们仍然会在链中的其他地方遇到 21 秒的延迟。

测试代码:

using System;
using System.Data.SqlClient;
using System.Diagnostics;

namespace test
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] timeouts = new int[] { 5, 1, 10, 20, 30 };
            string[] ips = new string[] {
                "DoesNotExist", // Host that does not resolve to an IP address on my network
                "192.168.0.1", // IP address that exists, only one host on the network, it is NOT running a sql service
                "311.1.15.82", // fictitious IP that does not resolve a host, should have same results as a name that doesn't resolve
                "192.168.0.181", // IP address that is on my subnet, but again does not resolve to a host at all.
            };
            foreach (var ip in ips)
            {
                Console.WriteLine($"Data Source: {ip}");
                foreach (var timeout in timeouts)
                {
                    using (var conn = new SqlConnection($"Data Source={ip};Initial Catalog=database_name;Integrated Security=True;Connect Timeout={timeout}"))
                    {
                        Console.Write($"Timeout: {conn.ConnectionTimeout}s");
                        var timer = Stopwatch.StartNew();
                        try
                        {
                            conn.Open();
                            timer.Stop();
                            Console.WriteLine($" - Connected in: {timer.Elapsed.TotalSeconds}s");
                        }
                        catch (Exception)
                        {
                            timer.Stop();
                            Console.WriteLine($" - Failed in: {timer.Elapsed.TotalSeconds}s");
                        }
                    }
                }
                Console.WriteLine();
            }
        }
    }
}

输出:针对 .Net Core v2.2.301 编译

Data Source: DoesNotExist
Timeout: 5s - Failed in: 7.1730095s
Timeout: 1s - Failed in: 2.2943659s
Timeout: 10s - Failed in: 9.754597s
Timeout: 20s - Failed in: 19.3288328s
Timeout: 30s - Failed in: 29.1020866s

Data Source: 192.168.0.1
Timeout: 5s - Failed in: 47.5502805s
Timeout: 1s - Failed in: 21.0405047s
Timeout: 10s - Failed in: 21.0482195s
Timeout: 20s - Failed in: 21.0320983s
Timeout: 30s - Failed in: 42.1433989s

Data Source: 311.1.15.82
Timeout: 5s - Failed in: 4.5533743s
Timeout: 1s - Failed in: 0.7421621s
Timeout: 10s - Failed in: 9.5509966s
Timeout: 20s - Failed in: 19.5665214s
Timeout: 30s - Failed in: 29.5764756s

Data Source: 192.168.0.181
Timeout: 5s - Failed in: 52.0493217s
Timeout: 1s - Failed in: 21.0335449s
Timeout: 10s - Failed in: 21.0365022s
Timeout: 20s - Failed in: 21.0402679s
Timeout: 30s - Failed in: 42.1391708s

我希望这一观察有助于找到真正的解决方案,请注意,运行此代码与其他早期版本的 .Net core v2 编译的代码非常相似。

【讨论】:

  • 我今天在 NUnit 中测试 appSettings.json 连接字符串时遇到了这个问题。据我所知,SqlConnection 的内部正在使用TcpClient.BeginConnect(),这似乎导致我在连接到网络上不存在的 IP 地址(或没有监听)时延迟 11 秒配置的端口)。当我避开SqlConnection 并使用var connected = tcpClient.ConnectAsync(hostname, port).Wait(millisecondsTimeout); 时,事物按预期连接或超时。我认为这是 TcpClient.BeginConnect() 中的 .NET Core 错误。
猜你喜欢
  • 2021-08-21
  • 2019-08-31
  • 2015-01-13
  • 1970-01-01
  • 2019-08-25
  • 2017-11-23
  • 2019-12-07
  • 2021-09-03
  • 1970-01-01
相关资源
最近更新 更多