本文由网易云 发布数据库
做者:郭忆
SQL Server 是 windows 平台 .NET 架构下标配数据库解决方案,与 Oracle、MySQL 共同构成了 DB-Engines Ranking 的第一阵营,在国内外企业市场中有着普遍的应用。
Mirroring 是 SQL Server 最经常使用的高可用解决方案,具备自动故障转移,高安全模式下具备数据“零”丢失,对客户端透明等优点,目前多家大的云计算厂商均采用该技术实现云端 SQL Server 高可用部署。今天,咱们就来聊聊 SQL Server 高可用镜像实现原理。
windows
镜像技术实现了位于不一样物理服务器上的两个 SQL Server 实例数据同步,在镜像集群中, SQL Server 实例具备三种角色:
○ Principal:具备完整的数据副本,对外提供数据库读写服务;
○ Mirror:具备完整的数据副本,自己不提供读写服务,经过接收来自 Principal 的更新日志实现数据同步,容许建立快照实现报表;
○ Witness:自己不存储数据,只负责在高安全运行模式下提供自动故障切换的能力,确保两个 SQL Server 实例只有一个对外提供服务,避免脑裂状况出现;
后端
在镜像集群中,principal 和 mirror 的数据同步是依靠事务日志来实现的,与 Oracle 和 MySQL 不一样,SQL Server 的事务日志是 Database 级别的,不是实例级别的,每一个 Database 都单独的事务日志,这也就使得 SQL Server 的镜像是能够基于 Database 层面实现。
一个 SQL Server 实例中的两个 Database,一个能够做为 principal,一个能够做为 mirror,分别与其余 SQL Server 实例组建镜像关系;另外,SQL Server 一个 Database 只能有一个 mirror 节点,一个 mirror 的 database 不能够再有 mirror 节点,这点与 MySQL 级联复制不一样;
缓存
SQL Server 的事务日志是物理记录级别的,记录了对数据库某个页的某行记录(slot)的操做,principal 建立镜像后,会启动一个单独的事务日志发送线程,维护一个虚拟的发送队列,而后读取事务日志,将其进行压缩,根据官方公布的测试数据,压缩比不低于12.5%,而后发送给 mirror 节点,mirror 节点接收到之后,会将其写入本地在磁盘上的一个重作队列文件中,而后再经过另外的一个线程异步的方式,从重作队列中获取事务日志,而后分发给应用线程(process unit)进行回放。
不一样于 MySQL Binlog,因为 SQL Server 的事务日志在 principal 上事务执行过程当中就已经源源不断的写入(MySQL Binlog 仅在事务提交阶段生成),在 principal 事务执行的同时事务日志就已经传递给了 mirror,因此基于事务日志的 SQL Server 的复制性能会更理想。同时,在 mirror 回放的过程当中,能够基于页(page)级别进行并发更新(redo parallel),在 SQL Server 的标准版中,仅提供一个线程进行事务日志回放(roll forward),在企业版中,若是当前服务器 CPU 大于5核,则每4个核,增长一个并行线程,若是低于5个核,则仍然使用单线程回放。同时,基于页的事务日志的并发执行,还有一个好处就是对于同一个页面的更新能够合并刷新,减小脏页刷新数量。
安全
镜像集群提供了三种运行模式:
○ 高性能模式:principal 与 mirror 之间数据异步传输,principal 上的事务提交无需等待 mirror 的响应,principal 宕机后,存在数据更新丢失的可能,不支持自动故障转移,能够经过强制服务的方式使得 mirror 提供服务。适合对数据可靠性要求不高,性能要求较高的业务场景,与 MySQL 的异步复制模式,Oracle DataGuard 最大性能模式相近;
○ 不带故障转移的高安全模式:principal 上全部的事务提交,都必需要确认该事务涉及的事务日志均已经传送到的 mirror 上,并写入 mirror 的重作队列中,持久化(是否持久化到外存设备还与 windows 操做系统写入缓存策略相关),mirror 返回确认后,才可提交,能够实现 principal 宕机下数据“零”丢失,不支持自动故障转移,能够经过手动转移或者强制服务方式使得 mirror 提供服务。与 MySQL 5.7 Loss-less replication、Oracle DataGuard 最大可用模式相近;
○ 带故障转移的高安全模式:与不带故障转移的高安全模式相比,增长了 witness (见证服务器),能够实现自动的故障转移,经过 witness,能够确保只有一个节点成为 principal,对外提供服务,实际上 witness 最重要的一个做用就是选主;
服务器
镜像集群故障转移最复杂场景就是带见证服务器的支持自动故障转移的高安全模式,因此咱们重点讨论该模式下的故障处理流程。
初始状态下,witness、principal 和 mirror 三个节点两两之间均保持长链接会话,如今讨论其中一方链接中断的状况:
网络
此时 witness 与 mirror 链接正常,触发自动故障恢复流程,principal 丢失 witness 链接会话,若是 principal 仍在运行状态,则将状态标记为 disconnected,表示失去与 mirror 链接,切断全部客户端链接,中止读写服务,等待故障切换。为了防止网络抖动引发没必要要的切换,会话超时默认时间为 10秒;witness 和 mirror 将 principal 标记为不可用,等待 mirror 上的重作队列中的事务日志回放(roll forward)完成后,mirror 成为新的 principal,开始对外提供读写服务。
架构
最后 mirror 会经过后台线程,将未提交的事务回滚(基于 binlog 的 MySQL 复制,因为 binlog 是在事务提交阶段生成的,因此不存在事务回滚的阶段)。
从整个故障切换的流程来看,故障切换时间主要包括三个部分:检测到 principal 宕机的时间、mirror 上重作队列中事务日志的回放时间以及回滚未提交事务的时间,其中前面两段时间服务不可用,尤为是重作队列的回放时间,直接决定了服务不可用时间。
并发
此时,principal 与 witness 链接正常,principal 状态变为 Disconected,表示终止与 mirror 链接,mirror 状态变为 suspend,principal 再也不向mirror 发送事务日志,等待 mirror 从新创建到 witness 链接后,principal 才会恢复与 mirror 进行数据同步。
less
principal 与 mirror 同时保持 witness 的链接会话,可是 principal 与 mirror 之间会话中断,witness 会通知 mirror,principal 依然保持链接状态,不会触发故障切换;此时 principal 因为保持有 witness 的链接会话,服务正常。
下面来考虑三方会话两个会话同时中断状况:
只要 mirror 与 witness 会话正常,便可完成正常的故障转移;若是 mirror 与 witness 链接也中断,则没法完成,即使是后来 mirror 与 witness 的会话优先恢复,则也没法故障切换,由于已然不肯定 mirror 是否拥有所有 principal 的数据,此时即使 principal 处于运行状态,也没法提供服务,等待 principal 与任意节点会话恢复正常,便可恢复读写服务;
不会触发故障切换,principal 切入公开运行模式(异步),即不会再向 mirror 发送事务日志,也再也不须要等待 mirror 的响应,直到 mirror 从新恢复会话。
不会触发故障切换,principal 继续提供读写服务,与 mirror 数据继续同步,镜像集群丧失自动故障转移能力,退化为不带故障转移的高安全模式;
若是三方会话同时链接中断,则 principal 没法提供服务,直到 principal 与任意节点通讯恢复正常。
场景1中,初始状态实例 A、B 和 witness 保持会话链接,其后,A 实例宕机,失去与其余成员的会话,实例 B 与 witness 保持会话,触发故障切换,实例 B 升级为 principal。其后实例 B 也宕机,服务中止。而后实例 A 恢复,可是因为此时实例 A 已是 mirror,不能肯定实例 A 拥有实例 B 的全部更新数据,因此没法故障切换,最后实例 B 恢复,服务恢复正常。
场景2 中,实例 A 和 B 同时失去了与 witness 的会话,可是服务已然正常,A 与 B 之间数据继续同步,其后 A 与 B 同时宕机,服务中止。最后 A 恢复服务,与 witness 恢复会话,A 继续提供服务。
一个完整的高可用机制除了后端节点的切换,还包括发生故障转移后,客户端如何可以快速地链接到冗余节点,继续业务读写。经常使用的实现,包括 Driver 层解决方案,例如 mongoDB replication set,也有经过二层内的广播方式实现 vip,例如 keepalived,固然还包括 proxy,以及三层 DNS 的实现。
SQL Server 的实现采用了 Driver 层处理的方式,开发者要实现自动的故障转移,在链接数据库时,除了必需要指定初始节点的 IP 和端口,还要指定故障转移的节点的 IP 和端口。客户端首先尝试使用初始节点建立链接,若是初始节点指向的实例当前为 principal,则链接会创建成功,能够正常的读写。当发生故障切换时,principal 会切断全部已有客户端链接,而后客户端创建到初始节点链接也会失败,经过必定的重试策略失败后,会尝试链接以前指定的故障转移节点,从而实现服务入口的切换。
SQL Server 经常使用的访问接口:OLE DB、ODBC、ADO 均支持指定故障转移节点,格式以下:
Server=250.65.43.21,4734; Failover_Partner=250.65.43.22,4734;
镜像集群的监控能够经过 SQL Server Management stdio 启动镜像监视器,或者系统内置的存储过程来实现,监控的主要指标包括:
○ 未发送日志:principal 上未发送的日志超过指定的阈值,会在 principal 上生成一个警告,在高性能模式下,强制服务时能够做为评估 principal 上事务丢失数量的依据,一样也适用于在高安全模式切换成异步模式状态下(mirror 失去链接)。
○ 未还原日志:重作队列中的未被应用的事务日志数量(KB),超过阈值,会在 mirror 上生成一个警告,该值能够做为评估故障转移时间的主要因素。
○ 最先未被发送的事务:principal 发送队列中,最先未被发送的事务距离如今的时间,单位时分钟,超过阈值,会在 principal 上生成警告,与未发送日志量一块儿,从时间维度,衡量高性能模式下和高安全异步模式下,数据丢失数量。
○ 镜像提交开销:高安全模式下,principal 上事务从提交到等到 mirror 响应的时间开销的平均值,若是超过阈值,则在 principal 上生成一个警告,在同步模式下,该值能够衡量同步开销。
参考文档:
msdn.microsoft.com/en-us/libra…
了解 网易云 :
网易云官网:www.163yun.com/
新用户大礼包:www.163yun.com/gift
网易云社区:sq.163yun.com/