深入解析 SQL Server 高可用镜像实现原理
作者:郭忆
本文由 网易云 发布。
SQL Server 是 windows 平台 .NET 架构下标配数据库解决方案,与 Oracle、MySQL 共同构成了 DB-Engines Ranking 的第一阵营,在国内外企业市场中有着广泛的应用。
Mirroring 是 SQL Server 最常用的高可用解决方案,具有自动故障转移,高安全模式下具有数据“零”丢失,对客户端透明等优势,目前多家大的云计算厂商均采用该技术实现云端 SQL Server 高可用部署。今天,我们就来聊聊 SQL Server 高可用镜像实现原理。
数据副本
镜像技术实现了位于不同物理服务器上的两个 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 三个节点两两之间均保持长连接会话,现在讨论其中一方连接中断的情况:
Principal 与 witness 连接中断:
此时 witness 与 mirror 连接正常,触发自动故障恢复流程,principal 丢失 witness 连接会话,如果 principal 仍在运行状态,则将状态标记为 disconnected,表示失去与 mirror 连接,切断所有客户端连接,停止读写服务,等待故障切换。为了防止网络抖动引起不必要的切换,会话超时默认时间为 10秒;witness 和 mirror 将 principal 标记为不可用,等待 mirror 上的重做队列中的事务日志回放(roll forward)完成后,mirror 成为新的 principal,开始对外提供读写服务。

最后 mirror 会通过后台线程,将未提交的事务回滚(基于 binlog 的 MySQL 复制,由于 binlog 是在事务提交阶段生成的,所以不存在事务回滚的阶段)。
从整个故障切换的流程来看,故障切换时间主要包括三个部分:检测到 principal 宕机的时间、mirror 上重做队列中事务日志的回放时间以及回滚未提交事务的时间,其中前面两段时间服务不可用,尤其是重做队列的回放时间,直接决定了服务不可用时间。

mirror 与 witness 连接中断:
此时,principal 与 witness 连接正常,principal 状态变为 Disconected,表示终止与 mirror 连接,mirror 状态变为 suspend,principal 不再向mirror 发送事务日志,等待 mirror 重新建立到 witness 连接后,principal 才会恢复与 mirror 进行数据同步。
Principal 与 mirror 连接中断:
principal 与 mirror 同时保持 witness 的连接会话,但是 principal 与 mirror 之间会话中断,witness 会通知 mirror,principal 依然保持连接状态,不会触发故障切换;此时 principal 由于保持有 witness 的连接会话,服务正常。
下面来考虑三方会话两个会话同时中断情况:
principal 与所有节点会话中断:
只要 mirror 与 witness 会话正常,即可完成正常的故障转移;如果 mirror 与 witness 连接也中断,则无法完成,即便是后来 mirror 与 witness 的会话优先恢复,则也无法故障切换,因为已然不确定 mirror 是否拥有全部 principal 的数据,此时即便 principal 处于运行状态,也无法提供服务,等待 principal 与任意节点会话恢复正常,即可恢复读写服务;
mirror 与 所有节点会话中断:
不会触发故障切换,principal 切入公开运行模式(异步),即不会再向 mirror 发送事务日志,也不再需要等待 mirror 的响应,直到 mirror 重新恢复会话。
witness 与所话中断:
不会触发故障切换,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 上生成一个警告,在同步模式下,该值可以衡量同步开销。
参考文档:请点击这里
了解网易云:
网易云官网:https://www.163yun.com/
新用户大礼包:https://www.163yun.com/gift
网易云社区:https://sq.163yun.com/
深入解析 SQL Server 高可用镜像实现原理的更多相关文章
- 深入解析SQL Server高可用镜像实现原理
本文来自网易云社区 SQL Server 是windows平台.NET架构下标配数据库解决方案,与Oracle.MySQL共同构成了DB-Engines Ranking的第一阵营,在国内外企业市场中有 ...
- sql server 高可用镜像
一.什么是数据库镜像 基本软件的高可用性解决方案 快速的故障转移恢复(3秒转移),低硬件成本 基于数据库级别的实现 二.数据库镜像中的服务器角色 主体服务器 承载主体数据库 接受用户连接和事务处理请求 ...
- SQL Server高可用——日志传送(4-1)——概论
原文:SQL Server高可用--日志传送(4-1)--概论 本文作为学习总结,部分内容出自联机丛书及其他书籍 日志传送是什么? SQLServer 2012之前(2012出现了AlwaysOn), ...
- SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn(实战篇)之AlwaysOn可用性组搭建
因为篇幅原因,AlwaysOn可用性组被拆成了两部分:理论部分和实战部分.而实战部分又被拆成了准备工作和AlwaysOn可用性组搭建. 三篇文章各自的链接: SQL Server ->> ...
- SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn可用性组(理论篇)
因为篇幅原因,AlwaysOn可用性组被拆成了两部分:理论部分和实战部分.而实战部分又被拆成了准备工作和AlwaysOn可用性组搭建. 三篇文章各自的链接: SQL Server ->> ...
- 京东云数据库RDS SQL Server高可用概述
数据库的高可用是指在硬件.软件故障发生时,可以将业务从发生故障的数据库节点迁移至备用节点.本文主要讲述SQL Server高可用方案,以及京东云RDS数据库的高可用实现. 一.高可用解决方案总览 1. ...
- SQL Server高可用——日志传送(4-3)——使用
原文:SQL Server高可用--日志传送(4-3)--使用 顺接上一篇:SQL Server高可用--日志传送(4-2)--部署 本文为本系列最重要的一篇,讲述如何使用日志传送及一些注意事项.从上 ...
- SQL Server高可用——日志传送(4-2)——部署
原文:SQL Server高可用--日志传送(4-2)--部署 前文再续,书接上一回.本章演示一下日志传送的具体过程 准备工作: 由于时间关系,已经装好了3台虚拟机,且同在一个域里面: SQL01:主 ...
- SQL Server ->> 高可用与灾难恢复(HADR)技术 -- AlwaysOn(实战篇)之建立活动目录域、DNS服务器和Windows故障转移群集(准备工作)
因为篇幅原因,AlwaysOn可用性组被拆成了两部分:理论部分和实战部分.而实战部分又被拆成了准备工作和AlwaysOn可用性组搭建. 三篇文章各自的链接: SQL Server ->> ...
随机推荐
- S2第一本书内测
<深入.NET平台和C#编程>内部测试题-笔试试卷 一 选择题 1) 以下关于序列化和反序列化的描述错误的是( C). a) 序列化是将对象的状态存储到特定存储介质中的过程 b) 二进制格 ...
- 解决Hystrix Dashboard 一直是Loading ...的情况
Hystrix是什么 Hystrix 能使你的系统在出现依赖服务失效的时候,通过隔离系统所依赖的服务,防止服务级联失败,同时提供失败回退机制,更优雅地应对失效,并使你的系统能更快地从异常中恢复. Hy ...
- 【数据结构】赫夫曼树的实现和模拟压缩(C++)
赫夫曼(Huffman)树,由发明它的人物命名,又称最优树,是一类带权路径最短的二叉树,主要用于数据压缩传输. 赫夫曼树的构造过程相对比较简单,要理解赫夫曼数,要先了解赫夫曼编码. 对一组出现频率不同 ...
- Linux下的进程与线程(一)—— 进程概览
进程是操作系统分配资源的基本单位.线程是操作系统进行运行和调度的基本单位. 进程之间可以切换,以便轮流占用CPU,实现并发.一般进程运行在用户模式下,只能执行指令集中的部分指令. 当进程进行上下文切换 ...
- hibernate框架学习笔记10:HQL查询详解
HQL语句中不可以出现与表有关的内容,而是对象的属性 实体类(注意配置文件): package domain; import java.util.HashSet; import java.util.S ...
- Leetcode 4——Partition List
Problems: Given a linked list and a value x, partition it such that all nodes less than x come befor ...
- beta冲刺4
昨天的问题: 我的社团数据库表项的处理,代码修改后结果无法显示. 帖子内容无法显示出来. 首页图像未替换 登陆整合没有完成 今天的完成: 服务器部署成功 页面背景修改.(已上传,未确认实装.) 任务截 ...
- 【Alpha版本】冲刺阶段 - Day4 - 加速
今日进展 袁逸灏:实现音乐的播放.(5h) 启动类,游戏画面类(修改类) 刘伟康:继续借鉴其他 alpha 冲刺博客,了解了Android方面的部分内容,便于更好地推进进度.(2h) 刘先润:更新图画 ...
- 四则运算----C++版
一.设计思想 因java中已做过,就是简单的将java中的语句调换为C++的语句. 二.代码 #include<iostream.h> #include<Stdlib.h> v ...
- mongodb 集群分片
分片 在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求 当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量,这 ...