SQL Server 2012 新一代的高可用技术AlwaysOn 之六 可读的辅助数据库

相对数据库镜像,AlwaysOn的一个重要优势就是可以将辅助数据库配置成可读模式。这极大地增强了数据库整体的伸缩性。通过将只读请求分流到辅助数据库,主副本的工作负载得到了减轻,读和写之间的冲突可以得到缓解,辅助副本的硬件资源也能得到利用。同时,通过AlwaysOn的“只读路由”功能,只读操作可以动态地被转向辅助副本。在一定程度上,可以实现对终端用户透明。利用这个功能,SQLServer可以实现工作负荷的Scale-out(由多台SQLServer同时响应客户端发来的工作负载)。对于高端应用,这的确是一个令人激动人心的新功能。

当然,主副本的数据和辅助副本上查询到的数据可能会存在一定程度的滞后。通常情况下,只要AlwaysOn工作正常,这个滞后时间一般都很短。当辅助数据库I/O较慢或者副本之间网络状况不佳的情况下,滞后时间可能会比较长。当辅助副本的数据移动挂起的时候,滞后时间就更长了。如果应用的读操作不能容忍任何程度的数据滞后,操作还是只能放在主副本上运行。

要让只读操作能“透明”地被自动转向辅助副本,必须解决下面三个问题:

1.      客户端要标明自己发来的操作是“只读”操作。这个判定是程序开发员在编写程序的时候,通过ApplicationIntent关键字指定的。而不是SQL Server端来判定的。

2.      辅助数据库要被配成可读模式。

3.      客户端的连接,要能够被重定向到可读辅助副本。AlwaysOn是用“只读路由”机制来实现的。

下面来详细介绍这几个问题。

ApplicationIntent关键字

为了支持AlwaysOn可用性组的可读辅助数据库功能,连接SQLServer 2012实例的客户端可以使用新的关键字“ApplicationIntent”来表示客户端发出请求的类型:“读/写”或是“只读”。这个关键字只能被设置为以下两个值中的一个。

ApplicationIntent=ReadOnly

ApplicationIntent=ReadWrite

目前支持该关键字的驱动有:

·        SQLNCLI11 ODBCOLEDB

·        .NET Framework 4.54.0System.Data.SqlClient

·        Microsoft JDBC Driver for SQL Server 4.0

设置ApplicationIntent关键字的方法取决于你使用的客户端工具。如果是一个自己开发的应用程序,就需要在连接字符串中指定这个关键字,例如:

Server=tcp:MyAgListener,1433;Database=Db1;IntegratedSecurity=SSPI;ApplicationIntent=ReadOnly;MultiSubnetFailover=True

 

如果是SQLServer Management Studio的话,你可以在连接属性中加入ApplicationIntent关键字。

                             

可用性副本的可读模式设定

你可以为每个可用性副本设置其作为主角色时的连接访问类型和其作为辅助角色时的连接访问类型。

在创建AlwaysOn可用性组的时候,就可以为每个副本设定其作为辅助角色的连接访问类型,在可用性组运行时也能随时对其进行更改。连接访问类型决定该辅助副本上的可用性数据库是否可以接受读操作。

辅助角色的连接访问类型分为3种:

1.      NONE:辅助数据库不接受任何类型的数据访问。

2.       READ_ONLY:当连接字符串中的Application Intent属性被设置成ReadOnly时,能被访问。

3.      ALL。任何连接都可以连接辅助数据库,但是通过这个连接,只有读请求才能够成功执行。任何尝试写数据库的请求都会失败。这个选项主要是用于那些无法使用ApplicationIntent关键字的客户端。

ApplicationIntent并不能保证从该连接上发出的请求都一定是读操作。它只是表示了该连接上“应当”发生的请求类型。因此无论把访问类型设置为ALL或者READ_ONLY,客户端程序都可能通过这个连接发送写请求到辅助数据库上。

 

主副本上也有两种设置,只能在可用性组创建完毕后,以通过修改可用性副本的属性来完成。主角色的连接访问类型有两种。

1.      ALL:主数据库同时允许读写连接和只读连接。这是主角色的默认行为。

2.      READ_WRITE:当连接字符串的ApplicationIntent 关键字设置为 ReadWrite 或未设置时,允许此连接。不允许连接字符串ApplicationIntent关键字设置为 ReadOnly 的连接。

当主副本设置为Read_Write时,如果一个客户端连接字符串ApplicationIntent关键字设置为ReadOnly,又要指定连接主副本,那这个连接会被拒绝。这样的设计会保证主副本不被应该由辅助副本完成的应用负载所干扰。

只读路由

你有两种方法来连接可读的辅助数据库。

·        客户端应用可以指定辅助副本的真实实例名,直接连接到该实例上。当辅助副本的连接访问选项设置为ALL时,客户端的连接字符串不用做任何特殊设置。当辅助副本设成READONLY时,客户端需要将ApplicationIntent设置为ReadOnly。由于是直接连接辅助数据库,不会发生任何的连接重定向。

·        AlwaysOn有一个叫做的只读路由(Read-Only Routing)的功能。当客户端连接使用Listener的名字来访问SQL Server实例时,只读路由功能可以将来自客户端的只读请求从主副本上自动重定向到可读的辅助副本上去执行。客户端应用程序只需要确保连接的服务器名是Listener的名字,而无需去关心背后到底是哪个副本响应这个请求。这个功能可以自动分流一部分主副本的工作负载,使得主副本有更多的资源处理其他读写请求。

如果可用性组有多个副本的话,你无法保证只读路由始终将所有连接全部重定向到相同的只读副本上。副本的运行状态的变化,副本的路由配置发生更改等因素都可能导致客户端连接到不同的只读副本。若要确保所有只读请求都连接到相同的只读副本,请使用指定可读辅助副本的实例名的方式来进行连接,而不要依靠只读路由。

实现只读路由功能需要以下条件:

1.      客户端应用程序使用TCP协议,通过Listener连接到主副本,而非直接通过主副本的实例名。

2.      客户端应用程序的连接字符串中,将ApplicationIntent属性设置为了ReadOnly

3.      至少有一个辅助副本被配置为可读辅助副本,且其连接访问设置必须是ALL或者READONLY

4.      已经为可用性副本配置了只读路由。这包括:

(1)        为每个副本设置一个只读路由URLread-only routing URL)。

(2)        为每个副本设置其作为主副本时的只读路由列表(read-only routing list)。

 

接下来详细介绍一下只读路由URL和只读路由列表。只读路由URL是一个如下形式的字符串:

'TCP://servername.domain.com:1433'

可以看出这个URL其实就是一个端点的形式。通常这个端点指向的就是副本本身。因此你要保证客户单可以通过URL中的服务器名和端口号来访问到这个副本。这个字符串会由主副本通过“重定向TDS”送回给客户端。

只读路由列表是一个表示可用性副本优先级的列表。在列表中的副本的名字都使用短名字。假设有一个包含3个副本(Node1,Node2Node3)的可用性组。在Node1上的路由列表可能是这样的:

'Node3','Node2'

这个列表表示只读请求会先被重定向到Node3。当Node3不可用的时候,请求就会被重定向到Node2。而Node2上的列表可能会是这样的:

'Node3', 'Node1'

您必须先设置只读路由URL,然后才能配置只读路由列表。

以下是一段联机丛书上的示例TSQL语句,用来展示如果在两副本的可用性组上配置只读路由URL和只读路由列表。假设这两个副本分别叫Computer01Computer02

只读路由使用以下过程来决定将只读请求重定向到哪台辅助副本。

前提条件:客户端在连接字符串中指定ApplicationIntent=ReadOnly,并且用Listener来连接可用性组。(如果不符合这两个条件,只读路由将不会工作。)

1.      连接请求会首先被指向到主副本上。

2.      主副本检查目标数据库,确认该数据库属于某个可用性组。

3.      如果数据库属于可用性组,再检查主副本上是否配置了只读路由列表。如果没有配置只读路由列表,那么只读路由还是不会工作。

4.      如果发现了只读路由列表,主副本就会按照列表的顺序依次检查每个副本,直到发现第一个连接访问设置为READONLYALL的可用副本为止。

5.      主副本把发现的那个副本的只读路由URL通过TDS包发还给客户端。

6.      客户端读取URL后即重新将自己定向到那个只读辅助副本。

所以对于每个用Listener名字发出的只读连接,它会先到主副本上转一圈,拿到只读辅助副本的URL以后,再连接到真正的辅助副本上。

辅助数据库上可能的性能问题

一个可读的辅助副本可能会同时受到读操作和写操作。读操作来自于直接连接它的客户端或者通过只读路由被重定向到它的客户端。而写操作只会来自于主数据库和辅助数据库之间的数据库同步。辅助数据库只有在重做日志的时候才会发生数据更改。客户端无法直接在辅助数据库上执行数据修改操作。

像其他所有数据库一样,只读辅助数据库也有可能遇到性能问题。由于其工作方式的特殊性,其性能问题也有所不同:

1.      使用行版本控制来消除阻塞问题

由于存在读写同时发生的可能性,在辅助数据库上可能会发生阻塞问题。为了保障读操作的稳定运行和性能,AlwaysOn使用行版本控制来消除辅助数据库上的阻塞问题。对辅助数据库运行的所有查询都会被自动运行在快照隔离级别之下。即使你显式的为查询设置了其他事务隔离级别,情况也是如此。此外,所有锁定提示(LockHint)都将被忽略。这些都有助于消除了读写操作互相争抢锁定数据所造成的阻塞问题。

虽然由于快照隔离级别的原因,读操作不会在数据上占用共享锁,但是快照隔离级别会导致读操作占用Sch-S锁。Sch-S锁还是会阻塞那些在辅助数据库上重做的DDL语句。因为那些DDL语句需要占用Sch-M锁,而Sch-M锁和Sch-S锁是互斥的。

除了阻塞,读操作的Sch-S锁还可能造成和写操作之间的死锁问题。为了保证数据同步的完整性,AlwaysOn规定来自于数据同步(重做日志)所做的写操作永远不会被选为死锁的牺牲者,无论该写操作的代价是多小。

2.       系统资源的争抢

如果读操作比较复杂,其所带来的CPUIO的负载也可能会影响辅助数据库上重做操作的性能。因此,如果你有一个需要长时间运行的只读操作,最好还是安排在非业务高峰时间来运行会比较好。

3.       索引

为了优化在可读辅助数据库上所执行的查询语句的性能,你需要在数据库上创建合适的索引。由于你无法在辅助数据库运行创建索引的命令,你需要在主数据上创建所需要的索引,然后让同步操作把索引给同步到辅助数据库上去。

4.       统计信息

统计信息对于查询操作的性能也有非常大的影响。正确的统计信息才能产生优化的执行计划。和索引一样,你只能在主数据上创建和维护统计信息,然后将统计信息的变更同步到辅助数据库上。当主数据上没有统计信息,或者统计信息已经很过时不再用适用于生成优化的只读操作执行计划的时候,你无法在辅助数据库上创建或更新统计信息。但是,辅助副本会在tempdb 中创建和维护辅助数据库的“临时统计信息”,用它们来替代过时的永久统计信息。一旦主数据库上的永久统计信息被更新了,辅助数据库上的永久统计信息也会被更新。这时,辅助数据库就会开始使用更新的永久统计信息,因为该信息比临时统计信息要新。

临时统计信息的名称会带有后缀“_readonly_database_statistic”,用于将其和主数据库上保存的永久统计信息区分开来。后缀_readonly_database_statistic 是保留关键字,在主数据库上手动创建统计信息时不能使用此后缀。只有SQL Server本身才能够创建和更新辅助数据库上的临时统计信息。但是,你可以在辅助副本的tempdb中使用DROPSTATISTICS Transact-SQL 语句删除临时统计信息。你也可以在辅助副本上查询sys.statssys.stats_columns 视图,来监视统计信息的状况。sys_stats 包含一个is_temporary 列,用于指示哪些统计信息是永久的,哪些统计信息是临时的。

因为临时统计信息保存在tempdb 中,所以重启SQL Server 服务会导致所有临时统计信息丢失。如果可用性组发生故障转移,所有辅助副本上临时统计信息都会被删除。

可读辅助副本会占用一部分tempdb的空间。临时统计信息,以及快照隔离级别的行版本信息都保存在辅助副本的tempdb中。因此对于辅助副本的tempdb需要进行合理的配置和优化,用以优化辅助副本的性能表现。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值