SQL Server连接问题案例解析(2)

在本篇博文中,我将为大家介绍一个在使用数据库镜像功能时发生的连接超时问题。关于数据库镜像的关键概念和术语,在之前的博客数据库镜像故障转移后,.NET应用程序连接SQL Server 超时(译文)中已经有了详细的介绍,这里不再赘述,大家可以参考前文。

 

问题描述

========

客户想要在Lync上安装一些组件,在后端需要从英国站点向澳大利亚站点的SQL Server建立连接时会如下错误:

英国站点:

服务器: lyncdben01

澳大利亚站点:

服务器: lyncdbau01

在问题调查的过程中,我们分别收集到了连接成功时与问题发生时的Netmon 日志。从dump 文件中,得到了Powershell命令背后真正的连接字符串:

Data Source= lyncdbau01.group.local\lyncdbau01;Database=xds;Max Pool Size=4;Connection Reset =false;Enlist=false;IntegratedSecurity=true;Pooling=true;Failover Partner= lyncdbau02.group.local\lyncdbau02;

 

问题分析

=========

1. 连接字符串很明确的告诉了我们,这是一个用于连接使用了镜像的数据库的连接字符串。如果一个连接尝试失败或者重试时间过期,则数据访问接口将尝试连接镜像的另一个伙伴。如果此时未打开连接,则数据访问接口还会尝试使用初始伙伴名称和故障转移伙伴名称,直到连接打开或登录期限超时。

重试时间为登录期限的某个百分比数。在后续的每轮中,连接尝试的重试时间会逐渐变大。在第一轮中,两次尝试的每次重试时间都是总登录时间的 8%。在后续的每轮中,重试算法会按相同的百分比增加最大重试时间。因此,前八次连接尝试的重试时间如下:

8%, 8%, 16%, 16%, 24%, 24%, 32%, 32%

重试时间使用以下公式进行计算:

RetryTime = PreviousRetryTime + ( 0.08*LoginTimeout)

其中,PreviousRetryTime 初始值为 0。

例如,如果使用默认的登录超时期限 15 秒,则LoginTimeout = 15。在这种情况下,前三轮中分配的重试时间如下:

轮次

RetryTime 计算

每次尝试的重试时间

1

0 +(0.08 * 15)

1.2 秒

2

1.2 +(0.08 * 15)

2.4 秒

3

2.4 +(0.08 * 15)

3.6 秒

4

3.6 +(0.08 * 15)

4.8 秒

 

 

 

 

 

 

 

 

 

 

下图说明了这些后续连接尝试的重试时间,每个重试时间均超时。

 

对于默认的登录超时期限,分配给前三轮连接尝试的最长时间为14.4 秒。如果每次尝试都使用了它的全部分配时间,则在登录期限超时之前仅剩下 0.6 秒的时间。在这种情况下,第四轮的时间会缩短,仅允许使用初始伙伴名称进行最后的快速连接尝试。但是,连接尝试可能会在其分配的重试时间内失败,尤其是在稍后的轮次中。例如,接收网络错误可能会导致在重试时间到期之前尝试便已结束。如果较早的尝试因网络错误而失败,则可以为第四轮(还可能包括更多轮)提供更多的时间。

https://msdn.microsoft.com/en-us/library/ms365783.aspx

2. 此时分析抓取到的Netmon日志会发现在问题发生时,客户端很快就close并reset了连接:

434 10:32:00 AM 3/4/2014 19.5784779 powershell.exe lyncdben01 lyndbaup01.tollgroup.local TCP TCP:Flags=...A...F, SrcPort=60709, DstPort=54994, PayloadLen=0, Seq=2129002479, Ack=1739112270, Win=256 (scale factor 0x8) = 65536 {TCP:75, IPv4:34}

 

435 10:32:00 AM 3/4/2014 19.6357220 powershell.exe lyndbaup01.group.local lyncdben01 TCP TCP:Flags=...AP...,SrcPort=54994, DstPort=60709, PayloadLen=617, Seq=1739112270 - 1739112887,Ack=2129002479, Win=256 (scale factor 0x8) = 65536 {TCP:75, IPv4:34}

 

436 10:32:00 AM 3/4/2014 19.6357463 powershell.exe lyncdben01 lyncdbau01.group.local TCP TCP:Flags=...A.R..,SrcPort=60709, DstPort=54994, PayloadLen=0, Seq=2129002480, Ack=1739112887,Win=0 (scale factor 0x8) = 0 {TCP:75,IPv4:34}

 

 问题原因

=========

这个问题实际上是由.Net Framework 3.5 或 .NET Framework 4 的一个已知问题造成的:

https://support.microsoft.com/en-us/kb/2605597/

当使用镜像数据库中连接的重试算法时,数据提供程序将等待一个读(SniReadSync)调用完成。这个调用发送到后端运行SQL Server的服务器,并且等待时间会被计算为连接超时时间乘以0.08 。但是,如果响应慢并且第一次SniReadSync 调用在等待时间过期时未完成,数据提供程序会错误的将连接设置为了doomed
状态。

注意:响应较慢问题在这种情况下可能由与服务端或网络的延迟触发。

解决方案

=========

这个已知问题已在.NET Framework 4.5.2中修复,因此对于.NET Framework 4,可以选择将其升级至4.5.2或更高版本来解决此问题。对于其他版本的. NET Framework,相应的修补程序也已经发布,可以通过安装相应的修补程序解决。详细信息,请参考:https://support.microsoft.com/en-us/kb/2605597/

这就是今天的分享,更多SQL Server案例学习请持续关注本博客的更新。