• 概述

From: http://book.2cto.com/201304/19868.html 


SQL Server过去几个版本所包含的高可用性和灾难恢复技术,也详细地介绍了它们彼此的优缺点。但有时用户对高可用性的要求非常高,任何一种现存的技术都无法完全满足要求,而把几种技术组合起来又会给部署和维护带来太多的复杂性。此时有没有一种更强大更完善的技术来满足用户所有的诉求呢?从SQL Server 2012开始,SQLServer引入了一种新的高可用技术,它的名字叫作AlwaysOn。而它可能就是你一直以来在寻求的解决方案。

AlwaysOn在开发初期代号叫作HADRon。从开发代号就可以看出,AlwaysOn是一种集合了高可用性(HA)和灾难恢复(DR)两种功能于一身的技术。从它的正式名称也可以看出,它的设计目标是尽可能地保持你的数据库系统永远可用。虽然永远可用更多的是一句口号,但是AlwaysOn相对于故障转移群集、数据库镜像和日志传送而言,的确是拥有许多优势。甚至可以说,AlwaysOn是这三种技术的集大成者。

AlwaysOn所支持的高可用单位,既不像Cluster一样,是整个SQL实例;也不像数据库镜像和日志传送一样,只能是单个用户数据库。AlwaysOn支持的,是一个“可用性组”(Availability Group)。每个可用性组是一个包含了一个或数个用户数据库的容器,可用性组里的所有数据库作为一个整体发生故障转移。

AlwaysOn利用了Windows故障转移群集的健康监测和自动故障转移的特性,因此它必须建立在Windows故障转移群集之上。但是和SQL Server群集不同的是,可用性组里的数据库并不是一定要求存放在共享存储(Shared Disk)上的,它们也可以存储在本地磁盘上。另外,可用性组是以用户数据库的集合为单位进行健康检测和故障转移的,而不像SQL Server群集那样是以整个实例为单位。

AlwaysOn具有以下这些关键特性。

1.像群集一样,AlwaysOn支持故障转移,但是它具有其独特的特点

多个用户数据库可以一同进行故障转移。这对要同时使用多个用户数据库的应用,例如Microsoft SharePoint,会很有帮助。

提供一个虚拟的服务器网络名,无论哪个服务器是当前的主服务器,客户端都可以使用统一的虚拟服务器名进行连接。

具有三种故障转移模式:自动、手动和强制,用户可以选择发生故障切换的条件。

一个主服务器可以对应最多达4个辅助服务器(总共5个服务器)。发生故障时可以切换到任意一个辅助服务器上。

有Dashboard可用于监视AlwaysOn的运行状态。有丰富的信息可用于故障诊断(DMV,性能计数器,扩展事件日志等)

得益于Windows Server 2008群集,可以实现多站点的部署。主服务器和辅助服务器之间可以在物理上相隔很远。

2.像镜像和日志传递一样,AlwaysOn在辅助服务器上有数据库的另外一份复制。所不同的是,这份复制可以支持更多的只读功能

每个辅助服务器上都有一份数据的复制,可以使服务器上的数据复制和主服务器上的数据完全同步。

辅助服务器可用于只读的访问请求。

辅助服务器可以执行备份和DBCC命令。

在某些配置情况下,客户端的只读请求可以被自动定向到辅助服务器。

可以自动修复某些类型的数据页面损坏问题。

主服务器和辅助服务器之间的数据会被加密和压缩,提高了安全性又降低了网络流量。

通过上面这些特性,相信你已经很清楚地看到,AlwaysOn集合了许多以往SQL Server高可用和灾难恢复技术的优点,同时又具有自己独特的功能。这些特性不但保证了SQL Server更高的可用性,而且还实现了一定程度上的负载均衡,减轻了SQL Server主服务器的压力。可以预期AlwaysOn将会成为SQL Server最炙手可热的高可用和灾难恢复的技术。


  • AlwaysOn的基本架构

From: http://book.2cto.com/201304/19869.html 

要部署一套AlwaysOn的方案,必须首先要部署一套Windows 2008或者Windows 2008 R2的群集环境。在Windows群集的结点上,你可以在群集的结点上安装SQL Server单机实例,也可以使用群集中的多个结点安装SQL Server群集实例。无论是单机实例,还是群集实例,只要这些实例上都配置了同一个AlwaysOn可用性组,这些实例就被称为该可用性组的可用性副本(Availability Replica)。AlwaysOn仅要求所有SQL Server实例都运行在同一个Windows群集上,但SQL Server实例本身不需要是群集模式的。如果没有特殊的理由,推荐所有的可用性副本都使用单机模式的SQL Server。

AlwaysOn可用性组里包含一个或多个用户数据库,这些数据库被称为可用性数据库(Availability Database)。每个可用性副本上都有这些可用性数据库的副本,这些数据库副本彼此之间互相同步。如果可用性副本是个单机实例,那么数据库副本就存放在该运行该实例结点的本地磁盘上;如果可用性副本是个群集实例,那么数据库副本就存放在共享磁盘上。

AlwaysOn可用性组从Windows群集角度来看,其实就是一个群集资源,因此可用性组中包含的所有数据库是作为一个整体在群集的结点间进行故障转移的。这使得AlwaysOn非常适合那些需要用到多个数据库的应用程序,避免了像数据库镜像那样只能切换单个数据库的问题。但是,可用性组不能包含系统数据库,也就是说系统数据库不能通过AlwaysOn实现高可用性,这点和数据库镜像是类似的。

在多个可用性副本间只有一个可用性副本上运行的数据库是处于可读写状态。这个可读写的数据库被称为主数据库(Primary Database),而这个可用性副本被称为主副本(Primary Replica)。其余的副本都被称为辅助副本(Secondary Replica),辅助副本上的数据库可能是不可访问的,或者是只能接受只读操作(取决于可用性组的配置),这些数据库被称为辅助数据库。一旦发生故障转移,任何一个辅助副本都可以成为新的主副本实例。主副本会不断地将主数据库上的数据变化发送到辅助副本,来实现副本间的数据库同步。

AlwaysOn可用性副本利用了Windows群集的特性来进行故障的侦测和转移,因此它也受到群集的一些限制:

一个可用性组中的所有可用性副本必须运行在单一的Windows群集上,跨不同Windows群集的SQL Server实例不能配置成一个AlwaysOn可用性组。

一个可用性组的所有可用性副本必须运行在Windows群集的不同结点上。运行在同一个结点上的两个不同实例不能用作同一个可用性组的副本。

如果某个可用性副本实例是一个SQL群集实例,那同一个SQL群集的其他非活跃结点上安装的任何其他SQL实例都不能作为它的辅助副本。

一个数据库只能属于一个可用性组。

你可以通过图3-1来理解AlwaysOn的可用性副本,可用组和群集结点的关系。

假设一个Windows群集分布在两个子网(Network Subnet A和Network Subnet B)里。在子网A,有三个结点。子网B有两个结点。结点A1与结点A2上安装了一个群集的SQL Server实例Instance 1。其他结点上分别安装了三个单机的SQL Server实例。这四个实例,就可以组成一个可用性组(Availability Group)。这些实例都是这个可用性组的可用性副本(Availability Replica)。在图3-1中所显示的状态下,SQL实例Instance 1是主副本,其他实例都是辅助副本。这些实例上都存储有同样的一套用户数据库组(Availability Database),但是只有Instance 1上的数据库是可读写的。

20130408100107799.jpg



 


如果Node A1或Node A2上安装有任何其他SQL实例,这些实例都不能被加入到这个可用性组中。

接下来,让我们了解另一个重要的AlwasyOn组件:Listener(侦听器)。

假设我们建立了如下的这个AlwaysOn方案。可用性组(Availability Group)名叫testAG,它拥有三个可用性副本,Denali1、Denali2和Denali3,如图3-2所示。

20130408100122395.jpg



 


Denali1现在是主副本,可用性组包含两个数据库:testdb1和testdb2。Denali1上还有一个不属于任何可用性组的数据库nonAGdb。在两个辅助副本Denali2和Denali3上,只有testdb1和testdb2这两个可用性数据库,没有其他数据库。

如果仅这样设置,在Windows故障转移群集管理器里就只能看到一个资源,即可用性组资源。但是SQL客户端不能使用这个资源的名字登录SQL Server。它们必须知道当前主副本的实例名称,使用这个名字来连接SQL Server。一旦发生了AlwaysOn故障转移,就需要通过修改应用程序的连接字符串、添加别名等方式来把应用程序重新指向到新的主副本上。在上面的例子里,用户开始时需要用Denali1这个名字来连接。如果AlwaysOn发生了故障转移,切换到了Denali2上,那所有的用户都要用Denali2这个名字来连接。这是非常不方便的。

为了可以让应用程序能够透明的连接到主副本而不会受到故障转移的影响,你需要创建一个Listener。一个Listener包含虚拟IP地址、虚拟网络名(DNS名)和端口号三个要素。创建了Listener之后,就会为可用性组资源添加虚拟IP地址和虚拟网络名资源。应用程序通过连接虚拟网络名而非主副本的实例名来访问到主副本实例和其上面运行的数据库,这点和故障转移群集很像。和故障转移群集不同的是,除了虚拟网络名可以使用外,主副本本身的真实实例名依旧可以被用来连接到这个实例。

还是上面那个例子。我们可以创建一个名字(即虚拟网络名)是testAGvname的Listener。从图3-3可以看到,SQL Server Management Studio既可以用Denali1这个名字,也可以用testAGvname这个名字来连接SQL Server。用testAGvname连接上SQL Server之后,除了可用性组中的数据库,你也可以看到nonAGdb,证明你已经通过testAGvname连接到了Denali1这个副本上了。

20130408100140737.jpg
 

SQL Server 2012以前版本的SQL Server,只有在实例启动的时候才会尝试绑定IP地址和端口。但是SQL Server 2012却允许你在副本实例处于运行状态的时候,随时绑定新的IP地址、网络名和端口号。因此可以随时为可用性组添加Listener,而且这个操作会立刻生效。当添加了Listener之后,则会在SQL Server的错误日志中看到类似这样的信息,如图3-4所示。

20130408100212896.jpg
 

不仅可以在创建可用性组的时候就为这个可用性组配置一个Listener,也可以在可用性组创建完毕之后再动态的添加或删除Listener。

要注意的是,SQL Browser服务是不支持Listener的。这是因为应用程序在使用Listener的虚拟网络名连接SQL Server时,是以一个默认实例的形式进行访问的(只有主机名,没有实例名),因此客户端根本就不会去尝试使用SQL Browser服务。

如果Listener使用的端口是默认端口1433,那么可用端程序可以很简单的直接使用虚拟网络名连接到主副本。但是如果Listener使用的端口是一个非默认端口,那么情况就有点复杂了:

(1)如果主副本实例是侦听在默认端口上,那么客户端通过Listener的虚拟网络名依旧可以直接连接到  主副本。其实客户端是使用了主副本侦听的1433端口,而非Listener所用的端口。

(2)如果主副本实例是侦听在一个非默认端口上,那么客户端就必须在连接字符串中指定端口号才能连接到主副本实例。有人可能会问,如果主副本上的SQL Browser服务在运行,客户端不能通过它找到主副本的端口从而连接上主副本吗?答案是不行。即使你的主副本是个命名实例,客户端在使用AlwaysOn虚拟网络名时还是会把它当作一个默认实例,从而根本不会发UDP包到1434端口去访问SQL Brower服务。于是也就没法通过主副本的SQL Browser获得主副本侦听的端口。

如果各个可用性副本所使用的端口不相同,有的副本使用1433端口,而有的副本使用非默认端口,你就必须在连接字符串中指定端口号。如果客户端仅使用虚拟网络名来进行连接,当主副本是使用默认端口的实例时,连接可以建立;但一旦发生故障转移,应用程序的连接就会失败。这会影响数据库服务的高可用性。所以按照现有的设计,我们建议加入AlwaysOn的SQL Server实例,最好使用同样的固定端口。


  • AlwaysOn的数据同步原理 

From: http://book.2cto.com/201304/19870.html 

数据库镜像技术一样,AlwaysOn会在各个副本上都维护一套数据副本。主副本上发生的数据变化,会同步到辅助副本上。所以和镜像一样,AlwaysOn也要完成三件事:

1.把主副本上发生的数据变化记录下来。

2.把这些记录传输到各个辅助副本。

3.把数据变化在辅助副本上同样完成一遍。

那AlwaysOn又是怎么做的呢?在主副本和辅助副本上,SQL  Server都会启动相应的线程来完成相应的任务。现在先从主副本谈起。

任何一个SQL Server里都有个叫Log Writer的线程,当任何一个SQL用户提交一个数据修改事务时,它会负责把记录本次修改的日志信息先记入一段内存中的日志缓冲区,然后再写入物理日志文件(日志固化)。所以对于任何一个数据库,日志文件里都会有所有数据变化的记录。

对于配置为AlwaysOn主副本的数据库,SQL Server会为它建立一个叫Log Scanner的工作线程。这个线程专门负责将日志记录从日志缓冲区或者日志文件里中读出,打包成日志块,发送给各个辅助副本。由于它的不间断工作,才使主副本上的数据变化,可以不断地向辅助副本上传播。

在辅助副本上,同样会有两个线程,完成相应的数据更新动作,它们是固化(Harden)和重做(Redo)。固化线程会将主副本Log Scanner所发过来的日志块写入辅助副本的磁盘上的日志文件里(这个过程被称为“固化”)。而重做线程,则负责从磁盘上读取日志块,将日志记录翻译成数据修改操作,在辅助副本的数据库上完成。

当重做线程完成其工作以后,辅助副本上的数据库就会跟主副本一致了。AlwaysOn就是通过这种机制,保持副本之间的同步。重做线程每隔固定的时间点,会跟主副本通信,告知它自己的工作进度。主副本就能够知道两边数据的差距有多远。

这些线程在工作上各自独立,以达到更高的效率。Log Scanner负责传送日志块,而无须等待Log Writer完成日志固化;辅助副本完成日志固化以后就会发送消息到主副本,告知数据已经传递完毕,而无须等待重做完成。其设计目标,是尽可能地减少AlwaysOn所带来的额外操作对正常数据库操作的性能影响。

读到这里,你或许会想,既然这些线程都是独立工作的,那主副本和辅助副本之间的数据差异量是怎么控制的呢?如何能保证主副本上的所有数据变化,都能被安全地传递到各个辅助副本上呢?AlwaysOn里有相应的机制,让这些线程相互协作。而副本之间是否允许有数据差异,则是由AlwaysOn的可用性模式决定的。

 

  • AlwaysOn的可用性模式

From: http://book.2cto.com/201304/19871.html 

可用性模式是每个可用性副本的一个属性。可用性模式决定了主副本在提交事务之前是否需要等待某个辅助副本将事务日志记录固化到磁盘。AlwaysOn 可用性组支持两种可用性模式:“异步提交模式”和“同步提交模式”。如果你曾经使用过数据库镜像,就会发现可用性模式的概念和镜像的概念(异步操作模式和同步操作模式)非常相似。

1.异步提交模式

使用此可用性模式的可用性副本称为“异步提交副本”。当辅助副本处于异步提交模式下时,主副本无须确认该辅助副本已经完成日志固化,就可以提交事务。因此,主数据库事务提交不会受到辅助数据库的影响而产生等待。但是,辅助数据库的更新可能会滞后于主数据库,如果发生故障转移,可能会导致某些数据丢失。如果为当前主副本配置了异步提交可用性模式,则它将通过异步方式为所有辅助副本提交事务,而不管这些副本各自的可用性模式设置如何。

对于主副本和辅助副本相隔很远而且你不希望小错误影响主副本性能的灾难恢复方案,异步提交模式将会很有用。而且,由于主副本不会等待来自辅助副本的确认,因而辅助副本上的问题从不会影响主副本。

在异步提交模式下,辅助副本会尽量与自主副本的日志记录保持一致。不过,即使辅助数据库和主数据库上的数据事实上是同步的,可用性组也始终认为辅助数据库处于“SYNCHRONIZING”状态(即“未同步”状态),因为理论上在异步模式下,辅助数据库在任何时点都可能会落后。

2.同步提交模式

使用此可用性模式的可用性副本称为“同步提交副本”。在同步提交模式下,主数据库在提交事务之前,主副本要等待同步提交辅助副本确认它已将日志固化到磁盘上。只要辅助副本还没有告诉主副本日志固化完成,主副本上的事务就不能提交。这样就保证两边的数据始终是同步的。只要一直在进行数据同步,辅助数据库就会保持“已同步”(SYNCHRONIZED)的状态。

同步提交模式能够保障给定的辅助数据库与主数据库上的数据保持完全的同步。但是这种保障的代价是主数据库上的事务提交会有滞后时间。可以说,同步提交模式相对于性能而言更强调高可用性。

为了优化AlwaysOn可用组在同步提交模式下的性能,SQL Server在AlwaysOn的工作线程和消息传递上动了很多脑筋。首先来看看,在辅助副本连接可用性组并与主副本建立会话之后,两者是如何同步日志的,如表3-1所示。

表3-1  同步日志步骤


步    骤行    为
1.连接辅助副本通过主副本的镜像端点建立两者之间的连接
2.请求数据辅助副本发出一个请求到主副本,要求主副本发送日志块。辅助副本和主副本会协商出一个日志块的LSN初始位置以及一些其他的信息
3.运行Log Scanner在主副本上,Log Scanner的工作线程开始工作。Log Scanner负责将日志块传送到辅助副本
4.固化和重做日志辅助副本会使用固化(Harden)线程和重做(Redo)线程的工作线程来处理Log Scanner发送过来的日志块,固化线程将日志块固化到辅助副本的磁盘上,而重做线程负责将日志中记录的事务在辅助副本上重新演绎
5.反馈进度每当辅助副本收到3条来自主副本的消息的时候,就把固化和重做的进度作为一个消息返回给主副本。如果超过1秒还没收到3条消息,进度消息也会被返回。反馈到主副本的消息里包含了哪些LSN已经在辅助副本上被重做和固化

 通过上述的过程,最终辅助数据库上已经固化的日志会赶上主数据库的日志末尾。此时辅助数据库的状态就会设置为 SYNCHRONIZED。这个同步阶段所需的时间主要取决于会话开始时辅助数据库滞后于主数据库的程度。另外,你需要明确重做线程和固化线程的区别,这点对理解事务提交的工作机制很重要。固化线程是将日志写入到日志文件,而重做线程是负责将日志中包含的数据更新真实地反映到数据文件上,这两个线程在AlwaysOn中是完全独立工作的。

接下里来看看在主副本上提交一个事务会发生些什么,如表3-2所示。

表3-2  提交事务的行为


步    骤行    为
1.提交事务在主副本上运行COMMIT TRAN命令来提交事务
2.写入到本地日志记录在主副本上,COMMIT TRAN命令会被写成一条日志记录(此时记录还在主数据库的日志缓存中)。然后主副本上的log writer工作线程会把直到COMMIT命令为止的所有日志记录组成一个日志块从缓存写入到磁盘上的LDF文件中。当日志被写入到磁盘之后,主数据库就开始等待来自辅助副本的消息来确认日志在辅助数据库上被成功写入磁盘。在这之前,该事务提交操作会保持等待
3.扫描日志当日志块开始被从缓存写入到磁盘上时,它也会发信号给Log Scanner工作线程,告诉Log Scanner“日志已经准备好了,可以被发送到辅助副本上”。
Log Scanner从缓存中取出日志块,把它发送给AlwaysOn的日志块×××(Log Block Cracker)。×××会搜索日志中那些需要特别处理的操作,比如file stream操作,文件增长等。×××会把这些操作作为一个消息发送给辅助副本。一旦日志块被解码完毕,整个日志块也会被作为消息发送给辅助副本
4.处理日志块消息日志块消息在辅助副本上得到处理。固化线程负责将日志固化到磁盘上。然后日志被保存到辅助数据库的日志缓存中,重做线程从缓存中获得日志块并开始执行重做操作
5.反馈进度每当辅助副本收到3条来自主副本的消息时,就把固化和重做的进度作为一个消息返回给主副本。如果超过1秒还没收到3条消息,进度消息也会被返回。进度信息中包含当前哪些LSN被固化了,哪些LSN已经被重做了。由于重做线程晚于固化操作启动,被固化的LSN可能会多于被重做的LSN
6.完成提交主数据库受到了辅助副本来的确认消息,完成事务提交处理并向客户端发送一条确认消息

 在同步提交模式下,日志块必须在主副本和辅助副本上都被固化到磁盘上,事务才能真正在主数据上提交。但是它并不要求日志在辅助副本上完成重做,这样可以减轻对主副本的性能影响。

另外,AlwaysOn会定期检查各个副本,以及副本上的各个数据库的健康情况。如果某个副本不能正常通信,那这个主副本和辅助副本间的连接进入DISCONNECTED状态。如果某个数据库不能正常进行数据同步,则这个数据库会进入“NOT SYNCHRONIZING”状态。

3.可用性副本之间的“DISCONNECTED”连接状态

AlwaysOn可用性组有一个会话超时机制。所有的主副本和辅助副本之间,会按固定间隔互相发送 ping。在会话超时期限内,如果收到 ping命令,就说明副本之间的连接正常。收到 ping 后,副本将重置此连接上的超时计数器。主副本和辅助副本之间就通过 ping来判断彼此是否依旧处于活动状态。

一旦某个副本因为网络故障、操作系统、SQL Server宕机等原因失去响应,它将不能按时把ping命令发给它的伙伴。如果主副本和某个辅助副本间的会话发生超时(没有收到辅助副本的ping),主副本和这个辅助副本之间的连接就会进入DISCONNECTED 状态。进入DISCONNECTED状态后,即使可用性副本处于同步提交模式,事务也不需要等待该副本的响应就可以在主副本上提交。

会话超时限制是一个可用性组级别的设置,你可以通过在SQL Server Management Studio中打开可用组的属性来修改它的值,默认值为10秒,允许的最小值为5秒。通常建议你将超时期限设置为10秒或更长。因为如果低于10秒,SQL Server在运行地非常繁忙,响应变慢的时候,可能会错误地进入DISCONNECTED状态。

4.辅助数据库的“NOT SYNCHRONIZING”状态

无论使用什么可用性模式,如果一个事务在辅助数据库上重做失败,就会导致辅助数据库进入“NOT SYNCHRONIZING”状态。和DISCONNECTED状态类似,此时即使可用性副本设置为同步提交模式,事务也可以在主副本上之间直接提交而无须等待辅助副本响应。

如果你想中断某个数据库的数据同步,而不想影响可用性组中的其他数据库,可以通过在Management Studio中选择Suspend Data Movement来手动挂起,如图3-5所示。挂起之后,该数据库在各个可用性副本(无论是什么可用性模式)上的状态都会变成“NOT SYNCHRONIZING”。

20130408101241390.jpg
 

本节的最后,要提一下可用性模式对事物复制的影响。如果你把主数据库作为复制的发布数据库,事务复制的Log Reader代理程序不会去处理那些尚未在辅助副本上固化的日志。因此,一旦辅助副本和主副本断开连接,那么复制就会停止工作。只有当辅助副本恢复和主副本的对话后,复制才能继续。此时主副本的日志可能会由于复制停止工作而变得很大。这种设计的主要目的是确保复制的数据发送速度,要慢于AlwaysOn的发送速度。因为辅助副本可能会通过故障转移成为新的主副本,从而变成新的发布服务器。如果复制跑得比AlwaysOn快,可能会发生订阅服务器比发布服务器数据更加新的情况。

 

  • AlwaysOn的故障转移形式

From : http://book.2cto.com/201304/19872.html 


前面我们介绍了AlwaysOn是如何实现副本之间的数据同步的。那它的另一大功能“故障转移”又是怎么实现的呢?

首先,来了解下AlwaysOn是如何发现可用性组出现问题的。

由于AlwaysOn可用性组是建立在Windows故障转移群集之上的,因此和SQL Server群集类似的,AlwaysOn可用性组也需要一个群集Resource DLL来连接Windows群集和SQL Server实例。由于可用性组是一个群集资源,Windows群集需要透过AlwaysOn的Resource DLL来控制资源的上线/离线,检查资源是否失败,更改资源的状态和属性,以及发生各种命令给可用性副本实例。你可以通过故障转移群集管理器查看可用性组资源的各种属性,如图3-6所示。

20130408101940342.jpg
 

AlwaysOn可用性组的资源类型是“SQL Server Availability Group”,该资源类型使用的Resource DLL的叫作Hadrres.Dll,在Hadrres.exe中定义了如何对AlwaysOn可用性组经行Isalive检查的方法。和SQL Server群集的Resource DLL(sqsrvres.dll)一样,Hadrres.Dll也是由群集的RHS.exe进程加载的。由于AlwaysOn可用性组使用的是非Windows群集自带的资源类型和Resource DLL,默认情况下Windows群集单独产生一个RHS.exe来专门加载hadrres.dll。这样即使该RHS.exe由于异常而崩溃,整个群集的其他资源也不会受到影响。

那么AlwaysOn可用性组是如何执行Isalive检查来判断它的健康状况的呢?还记得之前讲到过SQL Server 2012群集使用了存储过程sp_server_diagnostics来进行群集的健康检查吗?其实Always也是使用了sp_server_diagnostics来检查可用性组的健康状况。Hadrres.Dll会建立并保持一个连接到SQL Server,并通过这个连接运行sp_server_diagnostics,然后不断的获得诊断信息。sp_server_diagnostics的评估结果会被用来和AlwaysOn可用组的FailureConditionLevel设置向比较,来约定是够符合发生故障转移的条件。一旦条件满足,则可用性组就被切换到新的可用性副本上。更多关于sp_server_diagnostics存储过程的介绍可以参考第2章。

有几点需要注意的是:

可用性组也是一种群集资源,但是它的HealthCheckTimeout属性默认是30000毫秒,而不像群集资源那样是60000毫秒。所以可用性组的获取诊断信息并记录到扩展事件日志的频率更高。

无论你在一个实例上配置多少个可用性组,该实例上只会运行一条sp_server_diagnostics语句来诊断所有的可用性组。如果每个可用性组的HealthCheckTimeout设置不同,Hadrres.Dll会挑选最小的那个值并除以3来作为sp_serevr_diagnostics返回诊断信息的间隔(max(5, min(HealthCheckTimeout/3)))。这个最小的HealthCheckTimeout值被称为“有效HealthCheckTimeout”。

sp_server_diagnostics只是检测实例的健康状态,而不是检测每个数据库的状态。所以如果当前SQL Server实例还能正常工作,但可用性组所包含的数据库发生诸如数据文件损坏、置疑等问题而不能被正常使用,sp_server_diagnostics是无法发现问题的。就算你为当前的可用性副本配置了自动故障转移,这种情况下也是不会触发故障转移的。

当Windows群集触发故障转移后,故障转移目标(原先的辅助副本)能够接管主副本角色,对自己管理的数据库进行恢复操作,使它们作为新的主数据库。原先的主副本如果在故障转移后还可用,就会成为辅助副本,它上面的数据库就成为了辅助数据库。

AlwaysOn发现故障之后,是否会立刻触发故障转移呢?这取决于可用性副本的可用性模式和故障转移模式。

根据副本间数据同步的模式,可用性模式有两种:同步提交和异步提交。根据故障转移的方式,可用性副本也有两种故障转移模式:自动故障转移和手动故障转移。自动故障转移模式只有当副本的可用性模式为“同步提交”时才可以选择。

可用性模式和故障转移模式的组合形成了可用组的三种故障转移形式:自动故障转移、计划的手动故障转移(统称为“手动故障转移”)、强制手动故障转移(统称为“强制故障转移”)。表3-3列出了在不同的可用性和故障转移模式下支持的故障转移形式。

表3-3  不同的可用性和故障转移模式下支持的故障转移形式



异步提交模式同步提交模式以及手动故障转移模式同步提交模式以及自动故障转移模式
自动故障转移不支持不支持支持
手动故障转移不支持支持支持
强制故障转移支持支持支持

 需要注意的是,故障转移形式是由主副本和故障转移目标两者的模式所共同决定的。两个副本间要发生自动故障转移,需要两者都配置为同步提交模式+自动故障转移模式。两者中有一个配置了手动故障转移,则自动故障转移就不能发生。两者间有一个配置了异步提交模式,则它们之间就只能发生强制故障转移。

在三种故障转移形式中,只有强制故障转移可能会丢失数据。自动故障转移和手动故障转移会保证数据的安全。为了防止丢失数据,自动故障转移和手动故障转移都要求故障转移目标是使用同步提交模式的辅助副本且当时处于SYNCHRONIZED状态。如果已处于SYNCHRONIZED状态的辅助副本发出强制故障转移命令,其行为与手动故障转移时的行为相同。对于异步提交模式的辅助副本,无论数据是否已经达到同步,它永远只会处于SYNCHRONIZING状态,于是它只能支持强制故障转移这一种形式。

1.自动故障转移形式

自动故障转移使得AlwaysOn可用组成为了一种高可用方案,确保在丢失主副本之后快速使数据库再次变为可用。要发生自动故障转移,要满足这些条件:

当前主副本和一个辅助副本都设置为同步提交模式以及自动故障转移模式。

辅助副本必须与主副本同步。即辅助数据库处于SYNCHRONIZED状态。

主副本变得不可用,此时将发生自动故障转移。

当发生自动故障转移时,整个步骤是:

如果运行当前主副本的副本实例仍在运行,则它会将主副本和辅助副本的连接状态更改为 DISCONNECTED 并断开所有客户端的连接。

如果在故障转移目标副本上还有任何日志记录处于重做队列中,辅助副本会继续执行重做,以完成对辅助数据库的前滚操作。

完成前滚操作后,辅助副本就转换为了主副本,其数据库成为了主数据库。新的主副本将尽快回滚任何未提交的事务。

新的主副本在连接到一个辅助副本形成新的对话之前,会把自己置为 NOTSYNCHRONIZED状态。无论回滚操作是否已经结束,只要有辅助副本可以连接到新的主副本,主数据库就会转换为 SYNCHRONIZED 状态。

当原来的主副本解决了故障重新开始运行后,它会发现其他某个可用性副本现在变成了主副本,于是它就把自己转换为辅助副本,而其数据库将成为辅助数据库。当新的辅助数据库连接上新的主数据库后,辅助数据库就开始进行同步来赶上主数据库的日志末尾。

2.手动故障转移形式

当主副本和辅助副本连接在一起并且数据库处于SYNCHRONIZED状态,就可以执行手动故障转移。如果辅助副本停止运行,主副本不会受到影响。如果主副本停止运行,辅助副本将进入一种特殊的角色——“RESOLVING”角色(注意,RESOLVING是可用性副本的一种角色,而不是它所处的状态)。此时该副本既不是主副本也不是辅助副本,但可以执行强制故障转移把辅助副本转换成主副本,不过可能会因此承受数据损失。

当发生手动故障转移时,整个步骤和自动故障转移基本是一样的。它们的区别仅仅是在“谁触发了故障转移”。

你有四种途径来执行手动故障转移:

通过Windows的故障转移群集管理器来切换可用性组所在的资源组。

通过T-SQL语句。

通过SQL Server Management Studio使用UI来进行手动故障转移。

使用Powershell脚本。

只有设置为自动故障转移模式的可用性副本才允许通过Windows的故障转移管理器来切换主副本所在的实例。如果辅助副本没有设置自动故障转移模式,那么你只能使用其余三种途径来执行手动故障转移。

如果你尝试通过Windows故障转移群集管理器把可用性组手动转移到一个非自动故障转移结点,你会收到如图3-7所示的错误提示。

20130408102106155.jpg
 

如果你通过Windows故障转移群集管理器查看可用性组资源的属性,在“Advanced Policies”选项卡中你会发现非自动故障转移结点的副本根本就不在Possible Owners列表中,如图3-8所示。这也是为什么你会得到上面这个错误的原因。

请不要在该选项卡上手动把非故障转移模式的副本加入到Possible Owners列表中,因为这样会增加意外操作的可能性。非数据库管理员可能在不知情的情况下通过故障转移管理器将可用性组转移到一个异步提交的辅助副本上,从而导致一些意外的数据丢失。

如果你通过Windows故障转移群集管理器将可用性资源转入“离线”状态,那么所有可用性副本(无论使用什么可用性模式)上的数据库副本的状态都会变成“NOT SYNCHRONIZING”。而资源组的拥有者(即离线之前的主副本)的角色会变为“RESOLVING”。

我们建议始终通过SQL Server Management Studio来执行包括手动故障转移在内的所有可用性组的操作,这样能有效地防止Windows故障转移群集管理器上的错误操作而导致的意外,如图3-9所示。

20130408102125599.jpg


 


3.强制故障转移形式

从数据安全的角度来讲,强制故障转移是一个风险很大的操作。一旦执行了强制故障转移,主副本尚未发送到原来的辅助副本的任何事务日志都会丢失。这意味着,新的主数据库可能会缺少一些最近提交的数据。需要特别注意的是,强制故障转移后,剩余的所有辅助副本上的辅助数据库都处于挂起状态。在最坏的情况下,你可能需要重新初始化所有的辅助副本才能重新恢复可用性组。举例来说,假设你有三个可用性副本,主副本A和一个辅助副本B是同步提交模式,另一个辅助副本C是异步提交模式。当主副本A和辅助副本B的日志都比辅助副本C更加新的时候(这很容易发生),你执行了强制故障转移把主副本转移到C上。于是新的主副本C的日志晚于其余两个副本,这使得副本A和B无论如何都无法继续和副本C的对话。要重新恢复三个副本的配置,你必须以某个副本上的数据库为基础,重新在三个副本上配置可用性组。

你只能通过SQL Server Management Studio来执行强制故障转移。在转移开始前,SQL Server Management Studio会通过向导来和你确认你是否已经了解且愿意接受强制故障转移可能带来的后果,如图3-10和图3-11所示。

20130408102143458.jpg
 

4.多子网可用性组的故障转移

可用性组支持多子网环境,即可用性副本可以处于不同的子网当中。在2.2.5节介绍过,多子网的SQL Server群集一旦发生了故障转移,为了使得客户端能够更快的重新连接到新的活跃结点,你可以在连接字符串中使用MultiSubnetFailover参数并将其置为true。对于多子网的可用性组而言,在客户端程序中使用MultiSubnetFailover参数也能帮助客户端在可用性组发生不同子网间的故障转移时快速的恢复连接。要使用MultiSubnetFailover参数,除了客户端要使支持该参数的驱动程序外,你还必须要使用TCP协议并通过Listener来连接可用性副本。

无论可用性组是单子网还是多子网,都建议在客户端的连接字符串中将MultiSubnetFailover设置为true。对于单子网的环境,MultiSubnetFailover能够为迁移至多子网环境做好预先准备。一旦发生这样的迁移,你无须再去更改连接字符串。

20130408102157773.jpg
 

5.Split Brain(大脑分裂)

在理论上,如果发生故障转移,原先的主副本会先离线,然后某个辅助副本会上线。网络里不会同时出现两个主副本。但是在意外情况下,如果原先的主副本还没有离线,新的主副本就上线了,那一个可用组就出现了两个主副本。客户端可以连接其中的任何一个,做数据修改动作。就像人的大脑,被分裂成了两个。所以这种情况被起名为Split Brain(大脑分裂),是AlwaysOn要坚决杜绝的。所以在可用性组资源的属性中,你还能看到一个叫作LeaseTimeout的属性。Windows群集服务会定期跟它认为的主副本通信。如果主副本在“Lease Timeout”之前没有收到Windows群集服务的消息,它就自认为自己已经被群集服务切换掉了。这个SQL Server会自动终止自己的运行。因为Windows群集服务在任何一个时间点只会认定一个主副本,所以这样的方法可以避免“大脑分裂”。

6.连接、可用性副本和可用性数据库的状态

在前面的介绍中,你会发现AlwaysOn中的各种对象在不同的情况会处于各自不同的状态。如果你已经眼花缭乱,这里我们做一个小小的归纳。

连接状态:

Disconnected——说明辅助副本和主副本间已经断开了连接。

如果主副本发现辅助副本断开了和它的连接,在主副本上会将那些辅助副本上的辅助数据库标记为“未同步”,主副本等待辅助副本重新连接。

当辅助副本检测到它和主副本的连接断开后,辅助副本会尝试重新连接主副本。

Connected——辅助副本和主副本间连接正常。

可用性副本状态:

Not Synchronized——副本中的一个或多个数据库未同步或尚未连接到可用性组。

Synchronizing——正在同步副本中的一个或多个数据库。

Synchronized——辅助副本中的所有数据库均与主副本上的相应主数据库同步。

注意,不要将可用性副本的状态和可用性副本的角色(primary、secondary、resolving)搞混。

可用性数据库状态:

Not synchronizing

如果是主数据库处于该状态,说明该数据库未做好准备将其事务日志与相应的辅助数据库进行同步。

如果是辅助数据库处于该状态,说明数据库可能(1)由于连接问题或者重做失败,不再进行日志同步,(2)和主数据库的日志同步被“挂起”,(3)由于角色切换,正处于转换的中间状态。

Synchronizing

如果是主数据库处于该状态,说明该数据库已做好接受来自辅助数据库的同步请求的准备。

如果是辅助数据库处于该状态,说明该辅助数据库和主数据之间有正在进行同步的数据。

Synchronized

如果是主数据库处于该状态,说明它至少同步了一个辅助数据库。

如果是辅助数据库处于该状态,说明该数据库与相应的主数据库保持同步。

要注意,在异步提交模式下,可用性数据库和可用性副本永远不会处于“Synchronized”状态。