王方铭, 阿里巴巴技术专家, 从 DBA 到产品研发, 伴随阿里云数据库产品成长至今, 对数据库技术, 后端技术平台建设有深刻的理解, 目前主要负责 RDS SQLServer 产品研发工作.
早在 2015 年的时候, 随着阿里云业务突飞猛进的发展, SQL Server 业务也积累了大批忠实客户, 其中一些体量较大的客户, 在类似大促的业务高峰时, RDS 的单机规格 (规格是按照 "内存 * CPU*IOPS" 一定比例分配, 根据底层资源不同都会有各自上限) 已经不能满足用户的业务需求, 在我们看来也需要做 Scale Out 了.
但 SQL Server 并没有完备的中间件产品, 所以无论是逻辑 Sharding 还是只读分离, 都需要用户配合做应用改造, 而从用户角度看 Sharding 改动量很大, 不是一时间能完成的, 那么更多是寄希望于我们来提供读写分离的方案, 满足业务需求.
那么读写分离, 我们第一个想到的即是 AlwaysOn 技术. 但由于当时 AlwaysOn 对域控和 Windows 群集都是强依赖, 而这两者又对我们所依赖的基础设施有很大挑战, 需要做很多突破产品限制的非标准化操作才有可能实现, 并且还有安全风险. 所以最后我们只能放弃 AlwaysOn 技术方案, 重新设计方案帮助用户度过难关.
面对这类客户需求, 我们的方案如何产品化是值得思考的.
一, 产品快速发展
除了读写分离, 产品上还有很多更重要的问题急需我们去解决, 所以从 2015 年到 2017 年, 我们经历了一个飞速发展的阶段, 围绕产品稳定性, 多样性以及用户体验做了非常多的事情, 举几个点:
为了提高稳定性和用户体验我们最先替换了底层架构, 这也为后续产品多样化发展打下基础;
为了满足不同用户需求, 推出了 SQL Server 2008R2 / 2012 / 2014 / 2016 web / Standard / Enterprise 不同 Version,Edition 的组合版本;
为解决上云难问题推出了上云评估工具, 以及针对不同版本, 不同场景的上云方案全量备份数据上云 SQL Server 2008 R2 版, 全量备份数据上云 SQL Server 2012 及以上版本, 增量备份数据上云 SQL Server 2012 及以上版本, SQL Server 实例级别数据库上云;
为了提升用户体验支持更多特性, 我们在 SQL 层提供了很多封装的存储过程, 这里有些看似简单的功能在面对外部的安全, 内部的 SQL 镜像等因素的共同作用下, 实现的挑战还是很大的;
为了让专家服务更智能, 更能贴近每个用户, 我们研发了 SQL Server CloudDBA 集合了云上大量性能, 空间问题的解决方案.
在这当中依旧不断有读写分离的用户需求, 每次遇到, 我们都先引导到 IaaS 层用 ECS 自建实现. 因为 PaaS 化的时机并不成熟. 具体原因跟 SQL Server 当前的技术栈和云产品的结合有着密切的关系, 这里也可以把我们背后的一些思考分享出来.
二, 读写分离
首先明确我们讨论的读写分离是什么, MySQL 的读写分离大部分是利用中间层做路由解析, 基本上可以实现对应用端透明, 只有少部分场景需要用户做适配.
SQL Server 并没有成熟的中间件产品, 本质上讲, 是 TDS(Tabular Data Stream)不完全开放的原因, 如果要做也是有办法的, 只是投入的成本远大于收益. 基于此, SQL Server 无论利用当前何种技术实现读写分离, 对应用来讲都需要做一些适配. 即使是使用 AlwaysOn 技术, 在链接驱动的参数配置上也会不同, 所以我们后面讨论的读写分离都是基于这个前提.
三, 技术选型
我们对比了 SQL Server 所有相关的技术栈:
其中数据安全, HA(High Availability 高可用),DR(Disaster Recovery 灾难恢复)以及备库是否可读是我们最关注的.
这里的 HA 是指原生技术本身是否支持自动 HA, 当结合了部分云产品后, 我们也有能力把不支持变为支持. 数据安全和灾难恢复的时间基本是原生技术决定的, 备库是否可读是对单一技术的说明, 但做一些技术组合是可以把不可读变为可读的(比如 Database Mirroring + Database Snapshots).
最终综合来看 Transactional Replication 和 AlwaysOn 是我们觉得有机会做读写分离产品化的技术.
接着我们单独来看这两种技术对比:
原理上讲, Replication 是逻辑复制, 对比 AlwaysOn 的物理复制在性能, 延迟, 可靠性上都会有一定的差距. 在产品复杂度读, 可控性上和易用性上, 由于 Replication 过于灵活, 细到表, 列级别很难控制, 无论用户使用还是我们做产品化整个复杂度非常高, 所以最终我们选用 AlwaysOn.
四, AlwaysOn 技术
AlwaysOn 是原生支持 High Availability 和 Disaster Recovery 的技术, 本身又分为 Failover Cluster Instances(后续简称 FCI)和 Availability Groups(后续简称 AG), 下面的图是 FCI 和 AG 的基础架构:
其中 FCI 和常规版本的 AG 都依赖 Windows Server Failover Clustering(后续简称 WSFC). 不同点在于, FCI 是 Share Storage, 而 AG 是 Share Nothing;FCI 是实例级别同步, 而 AG 是 DB 级别.
那么很容易想到, Share Nothing 会有同步和异步的区别(和镜像技术类似), 其中两者的区别点需要我们知道 AlwaysOn 的基本同步过程:
首先在 Primary 节点的日志 (Commit/Log Block Write) 会从 Log Cache 刷到磁盘, 同时 Primary 节点的 Log Capture 也会把日志发送到其它所有 Replica 节点, 对应节点的 Log Receive 线程把收到的日志同样从 Log Cache 刷到磁盘, 最后会由 Redo Thread 应用这些日志刷到数据文件里.
这其中还有一步, 就是在 Secondary 端刷日志的时候, 如果 Primary 节点等待这次返回的 Acknowlege Commit, 那么就是同步模式; 反之如果 Primary 端不等 Secondary 的返回, 那么就是异步模式, 两者的区别由此展开.
这是基本的同步过程, 但无论是 AlwaysOn 还是 Database Mirroring 都存在一种情况, 即同步模式下如果 Secondary 端异常, Primary 端没有收到它的心跳, 也没有收到这次的 Acknowlege Commit, 那么也并不会算作写入失败.
因为它一旦认定 Secondary 异常, 就不会等这次 ACK, 而是退化为类似异步的模式, 但会把 Secondary 端的异常状态记录在基表里, 通过相关视图 :sys.dm_hadr_database_replica _states,sys.database_mirroring 暴露出来, 就是我们常见的 NOT SYNCHRONIZING / Disconnect 状态.
这时候自动化运维系统或者 DBA 就需要做判断处理, 等到 Secondary 修复重新联机后, 会向 Primary 报告 End of Log (EOL) LSN,Primary 端再向它发送 EOL LSN 之后 hardened 的所有日志.
一旦 Secondary 端开始接收到这些日志, 并逐步刷到日志文件中, 那么整个 AG 或者 Mirroring 相关的视图又会标记其状态为 Synchronizing, 表明正在追赶, 直到 Last Hardened (LH) LSN 达到主备一致状态, 这时重新回到同步模式.
以前的情况一直是这样. 直到 SQLServer 2017 CU 1 引入了 REQUIRED_SYNCHRONIZ ED_SECONDARIES_TO_COMMIT 这个参数, 参数名字很长, 但也基本包含了它的作用, 应对刚才的场景是可以让 Primary 端一直等到 Secondary 节点重新联机并同步后再提供服务.
了解了 AG 同步, 异步以及 FCI, 再总结下我们关心的点:
在实际方案中, 这些也可以结合起来, 最终再和阿里云产品整合做一个整体方案. 之前也讲到, 阿里云从 15 年就开始做类似方案来解决用户问题, 一直到最终 PaaS 化, 也过度了三个版本.
五, 云上演进
第一版本我们使用了 ECS,SSD 云盘, OSS,VPC,SLB 作为基础; 在 SQL 技术上, 我们使用 SQL+WSFC+AD 的方式, 目前看这种方式支持的版本也非常多, 从 12 到 17 都可以; 验证方式既可以用域控也可以用证书.
但有 2 个缺点:
成本高. 除了 Primary 和两个 Secondary 节点, 还要有两个 AD 节点, 毕竟我们每个环节都要保证高可用;
稳定性不够. 网络抖动的情况非常容易让 WSFC 判断异常, SQL 端 DB 同时出现不可用.
这是第二版的架构, 跟第一版相比, 我们用到了 HAVIP 来解决监听器问题, 去掉了 AD 只能用证书做验证, 但也因此最小资源开销降低到 3.
这个方案也是之前在阿里云上用的比较多的, 但同第一个方案一样, 在网络稳定性上会有很多挑战, 因为我们未来面对的场景不只是同城跨可用区, 还会有更多跨 Region 以及打通海外的场景, 所以这个方案也只能 Cover 一部分用户的需求, 但对我们不是一个最终方案.
最终我们找到了方案三, 去除了 WSFC 和 AD, 只关注基础云产品和 SQL 本身.
最重要的是跟方案二相比, 对网络的抖动敏感度会更低也更可控, 最多是在 Primary 端出现 Send Queue 的堆积, 这个我们完全可以通过 SQLServer 相关的 Performance Counter 监控并做一些修复调整.
但没有方案是完美的, 可控性强的代价是, 这种无群集无域控架构原生是不具备 HADR 能力的, 这点熟悉 WSFC 的同学可以知道. 之前架构的 HA 都是依赖 WSFC, 包括健康检查, 资源管理, 分布式元数据通知维护以及故障转移, 所以这时候就必须我们自己去解决这个问题.
为此我们也做了很多努力, 最终实现了支持 AlwaysOn 无域控无群集的 HA 系统, 不依赖 Cluster 完全自主可控的 HA.
六, 产品化
最终的产品架构如下, 首先会保证有 2 个同步节点做主备, 并且尽量分配在不同的可用区, 其它只读节点默认是异步, 最多可以有 7 个只读节点; 用户的访问链路可以有三种:
读写链路: 会指向两个同步节点, 由我们的 HA 来保证高可用;
统一只读链路: 根据用户需求设定, 把指定的 Replica 节点绑定到一起按照一定的权重比例分配链接;
单一只读链路: 即每个只读节点会提供一个单独的链接, 让用户也可以自己灵活配置, 比如用户的 App Server 就是在可用区 A, 那么就可以直接访问可用区 A 的只读地址, 避免再通过统一只读被路由到其它区域.
至此, SQLServer AlwaysOn 已经在阿里云 PaaS 化, 当然目前只是支持最主要功能, 后续还有很多可以完善丰富的地方. 如果大家有任何好的建议或者问题, 也很欢迎留言与我交流.
来源: http://database.51cto.com/art/201810/584680.htm