在数据库镜像中,数据访问接口(data access provider)会缓存SQL Server返回的镜像服务器名。我们也可以在连接字串中指定故障转移伙伴(Failover Partner)。但是,如果连接字串中提供的故障转移伙伴与缓存的镜像服务器名不一致时会有什么情况发生?数据访问接口会如何重定向客户端的连接?
下面这篇技术博客列举了7种情况。
该文章已详细解释了多种行为,但是对于缓存的镜像服务器如何被使用,描述的并不是很清楚。
本文将进一步给出一些相关说明。
- 具有客户端重定向功能的三个接口为:
- SQL Native Client
- SQL Server 2005 的ADO.NET 2.0接口(SqlClient)
- SQL Server 2005 JDBC (Java Database Connectivity) 1.1 驱动
- 完成一个到主体服务器的新连接后,数据访问接口将下载当前镜像服务器的服务器实例名。此名称作为故障转移伙伴名称被存储在缓存中,从而会覆盖连接字串中提供的故障转移伙伴的名称(如果有)。
- 缓存会被存储在客户端的内存 (volatile memory)中(对于托管代码,缓存的作用域限定为应用程序域,- application domain)。
- 当主体服务器已经建好并能够运行,随后从客户端到主体服务器的连接也应当是成功的。
- 当同一客户端由于某种原因(例如,服务器太忙、网络太忙等)不能连接到主体服务器,它就会尝试去连接缓存的伙伴名(即镜像服务器)。在没有发生故障转移的情况下,客户端是无法连接到镜像服务器的,连接最终失败。接下来,会有两种情况:
- 客户端的代码中有重试逻辑,进行重试连接而并不关闭进程后,
a) 成功连接到主体服务器
或者
b) 重连接失败,那么它会再尝试缓存中的伙伴服务器(即镜像服务器)。根据重试逻辑,客户端可能会重试几次,直到成功连接到主体服务器。这意味着,你会在镜像服务器上看到几个”login failed”事件(因为镜像服务器不可访问)
- 客户端退出当前进程并重启。然后尝试重新连接SQL Server主体服务器,
a) 成功连接到主体服务器
或者
b) 重连接失败,而后它会尝试连接字串中指定的故障转移伙伴服务器。这是因为,对于一个新的连接,镜像服务器从没有被缓存过。
总结得来说,如果有缓存存在,客户端会使用缓存的服务器名,缓存的名字是由 SQL Server(而不是连接字串中的)返回的;如果缓存不存在(比如,当应用程序创建了一个到SQL Server的新连接),客户端将使用连接字串中的故障转移伙伴服务器名。
我用UDL文件测试了上面的行为。
环境:
建立带有数据库镜像的两台服务器。服务器A作为主体服务器,服务器B作为镜像服务器。
两台服务器上都开启审核“login success”和“login fail”事件。
情景1:
- 在客户端服务器上创建名为test.UDL的文件。
- 打开test.UDL文件。
- 在Provider标签上,选择“SQL native client”或者“SQL native client 10.0”或者ODBC drivers。
- 在All标签中,设置Data Source(数据源)为“server A”, Failover Partner(故障转移伙伴)为“server A”(即一个不正确的镜像机), Initial Catalog(初始目录)为镜像服务器数据库名,Integrated Security(集成安全性)为SSPI。
- 打开Connection标签,点击Test Connection(测试连接)按钮。这应该是成功的。现在,这个连接缓存了真正的镜像服务器名 (即server B),在服务器A的日志中我们可以看到“login succeeded”事件。
- 不要关闭test.UDL窗口,并手动进行故障转移。(即服务器B变成主体服务器)。
- 再次点击Test Connection。 尽管在连接字串中没有指定服务器B,但连接还是会成功。我们会在服务器B中会看到login succeeded事件。
场景2
- 现在,我们关闭UDL文件然后重新打开。
- 再次点击“Test Connection”,会出现“login failed”错误 (即连接失败)。这是由于服务器A是连接字串中的故障转移伙伴,所以会有两次尝试到服务器A的连接。我们会在服务器A中看到“login failed”事件,但是在服务器B中没有事件,因为服务器B没有被缓存过。
参考文档:
建立到数据库镜像会话的初始连接