网站故障公告3:应该找到了问题的真正原因

根据故障期间的错误信息:

Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

找到了这三篇博文:

1. ADO.NET application connecting to a mirrored SQL Server Database may timeout long before the actual connection timeout elapses, sometimes within milliseconds

2. Interesting SQL Server Mirroring Problem

3. You may see an instant timeout when connecting to a SQL Server Mirrored database from a .Net application

谈到的都是SQL Server数据库镜像引起的"Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding." 尤其是第3篇中的一段文字:

As per the Connection Retry Algorithm for Mirroring, SqlClient code takes the connection timeout and multiplies it by 0.08 to determine the milliseconds to wait for first read (SniReadSync call). Now if this first SniReadSync fails due to a timeout (due to a slow response from the server), the connection is incorrectly set to a doomed state by the sqlClient .NET Provider and this causes the connection attempt to prematurely fail before the entire connection timeout expires.

联想到阿里云RDS与我们之前自己的物理服务器、阿里云云服务器时最大的不同之处是:阿里云RDS使用了SQL Server数据库镜像。

立即眼前一亮!问题的真正原因就在这——ADO.NET对SQL Server数据库镜像处理上的bug。

故障是这么发生的:

1. 我们在博客程序的连接字符串中设置的是Connect Timeout=30(默认是15);

2. SqlClient将 30(Connect Timeout) × 0.08 = 2.4s 作为超时时间发起一次数据库连接操作;

3. 对于SQL Server数据库镜像的场景,SqlClient只对Principal数据库发起1次且仅此1次数据库连接操作(不合理,至少失败时重试一次);

4. 如果超时,SqlClient就会去连接“连接字符串”中通过Failover Partner指定的镜像数据库;(4月17日故障时就是发生了超时情况)

5. 而我们在连接字符串中没有指定Failover Partner,SqlClient也没有镜像数据库可连,于是SqlClient就自以为是地Timeout。

这是ADO.NET的一个bug,微软在2011年就确认了这个bug,说是在下一版本中(也就是现在的.NET Framework 4.5)会修复这个问题。

Microsoft has confirmed that this is a problem in the current release of ADO.NET. This issue will be fixed in ADO.NET version, ships with Visual Studio 2011.

而我们的博客程序用的是.NET Framework 4.0,没能躲开这个bug的魔爪。

目前还不知道.NET Framework 4.5是不是真的解决了这个问题。

真没想到,最终竟然是被微软坑的!

临时解决方法:在连接字符串中设置Connect Timeout=150,并从网络与数据库层面尽量减少连接时间。

补充:有人在阿里云论坛上提到“之前用RDS时就会偶尔出现秒级以上的延时”,这可能也是一个肇事者。

更新:“问题的真正原因”背后的真正问题是为什么数据库连接会超时(注:只是连接,查询还没开始)?

相关博文:

网站故障公告1:使用阿里云RDS之后一个让人欲哭无泪的下午

网站故障公告2:找到问题的重要线索

posted @ 2013-04-17 01:41  博客园团队  阅读(14976)  评论(117编辑  收藏  举报