Share via


连接数据库镜像出现超时(timeout)的可能原因

 

你的数据库是做了镜像的数据库,然后你在程序里面连接这个数据库。但是有时候你发现您的程序比连接非镜像数据库的更容易出现连接超时(timeout)。这里面一个可能原因就是客户端程序连接镜像数据库和非镜像数据库的方式是有差别的。

 

 

当数据库是镜像数据库的时候,你在connection string路面指定的timeout值和非镜像数据库的timeout值尽管大小一样,但实际上效果是不一样的。对于镜像数据库,客户端数据库接口(通常是SqlClient 或者SQL native client)有连接重试算法。非镜像数据库是没有的。连接重试算法如下:

假定你指定connection timeout 15 秒:

第一轮:连接主机,超时时间为总timeout的8% 即:15*8%=1.2秒

这时候如果连接没有成功,就试图连接备机,超时时间也是1.2秒。

 

第二轮:如果连接备机失败,这时候,客户端数据库接口再试图连接主机,超时时间设为

总timeout的16% 即:15*16%=2.4秒。 如果没有成功,就连接备机,超时时间也是2.4秒。

 

第三轮,超时时间是总timeout时间的24%。在后续的每轮中,连接尝试的重试时间会逐渐变大。前八次连接尝试的重试时间如下:

 

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

 

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

 

RetryTime = PreviousRetryTime + ( 0.08 * TotalLoginTimeout )

 

例如,如果使用默认的登录超时期限 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 秒

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

 

也就是说,对于15秒的timeout值,实际连接主机的最大timeout值是3.6秒! 如果前面3次连接(1.2秒,2.4秒,3.6秒)都不成功,那么15秒超时时间就到了,你程序就会报超时错误。

 

要增加连接主机的真实timeout值,你只能增加总的connection timeout值。比如如果超时设为120秒,那么第一轮的重试时间是:

 

120*8%=9.6秒。

 

即便如此,第一轮的尝试连接时间还是比非镜像数据库的缺省15秒timeout时间要短。

 

具体请参考如下文档:

Connection Retry Algorithm (for TCP/IP Connections

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