我们有一个特定的 SQL Server,它在接受连接时会间歇性地超时。这个问题在一天中是一致的,但发生率非常低。如何继续排除故障?
连接超时已过期。尝试使用登录前握手确认时超时时间已过。这可能是因为登录前握手失败或服务器无法及时响应。尝试连接到此服务器所花费的持续时间是 - [Pre-Login] 初始化 = 0;握手=15002;(Microsoft SQL Server,错误:-2)
服务器配置:
- SQL Server 2016 SP1 CU5 Enterprise(在 SP1 之前也出现过问题)
- 服务器和客户端上的 Windows Server 2012 R2
- HP ProLiant DL360 Gen9 上的 VMware ESXi,6.5.0
- VM 有 8 个 vCPU,64 GiB 内存(完全保留)
测试脚本(每秒执行一次):
$failed = $false;
$loginDuration = (Measure-Command {
$ncon = New-Object System.Data.SqlClient.SqlConnection `
@( 'Data Source=1.2.3.4,16143;Database=Test;User=Test;Password=****;Pooling=false;' );
try
{
$ncon.Open();
$cmd = New-Object System.Data.SqlClient.SqlCommand `
@( 'SELECT @@VERSION', $ncon );
$cmd.ExecuteNonQuery();
$ncon.Dispose();
}
catch
{
$failed = $true;
}
}).TotalMilliseconds;
Write-Metric -metric 'itp.dbserver.logintime' -unit 'milliseconds' `
-value (&{if ($failed) { 120000 } else { $loginDuration }});
观察:
- 在操作系统更新、SQL Server 更新、San 移动以及从 Hyper-V 移动到 VMWare 之后开始出现问题
- 大多数连接成功(1,440 次尝试中有 4 次失败)
- 在“[Pre-Login] 初始化 = 0;”中,失败总是以小数字列出 并且“握手= 15002”中的数字很大。我们没有收到诸如“未找到”或“不知道这样的主机”之类的错误,只有“连接超时”
- 没有为监听器启用加密
- Ping 显示在较长时间内没有丢失(发送的 96,045 次中有 0 次丢失)
- 所有防火墙都被禁用
- 尝试使用 IPv6 和 IPv4 地址的连接失败率相同
- CPU 偏低 (<40%)
- 活跃会话持续在 400 左右
- 气球驱动程序已禁用
- 一旦建立的连接是稳定的,执行查询时没有意外错误,没有奇怪的断开连接。
- 多个客户端在连接时遇到问题 - 来自多台计算机的 ODBC 和 ADO
更新:我终于得到了一个失败连接的客户端 Wireshark 跟踪。没有明显的数据包丢失,客户端实时接收 TCP ACK(<10ms)。发生故障时客户端使用 DNS 名称,但使用连接字符串中的 IPv4 地址确实会发生故障。
我是否正确地认为,我收到对发送的登录前请求数据包的即时 TCP ACK 会将问题本地化到操作系统或 SQL Server 的事实?
这最终被确定为 VMWare LRO 的副作用。禁用基于主机的 LRO 解决了该问题。看