作者介绍了阿里巴巴技术专家王方明。从DBA到产品开发,随着阿里云数据库产品的开发,对数据库技术和后端技术平台建设有着深刻的理解。负责RDSSQLServer产品开发。早在2015年,随着阿里云业务的快速发展,SQLServer业务也积累了大量忠实客户,其中不乏规模庞大的客户。它按照“内存*CPU*IOPS”的一定比例进行分配,根据不同的底层资源会有各自的上限),已经不能满足用户的业务需求。我们认为,还需要ScaleOut。但是SQLServer并没有完整的中间件产品,所以无论是逻辑分片还是只读分离,都需要用户配合应用改造,而从用户的角度来看,分片的变化是非常大的,不能短时间内完成,所以更希望大家提供读写分离的方案来满足业务需求。那么读写分离,我们首先想到的就是AlwaysOn技术。但是,由于当时AlwaysOn强烈依赖域控制器和Windows集群,两者都对我们所依赖的基础设施提出了很大的挑战,所以才有可能做很多突破产品局限的非标准化操作,并且仍然存在安全风险。所以***我们只能放弃AlwaysOn的技术方案,重新设计方案来帮助用户渡过难关。面对这样的客户需求,如何将我们的解决方案产品化,是值得思考的。1、产品的快速发展除了读写分离,产品还有很多更重要的问题亟待解决。因此,从2015年到2017年,我们经历了一个快速发展的阶段,注重产品的稳定性、多样性和用户。体验做了很多事情,这里有几点:为了提高稳定性和用户体验,我们完全更换了底层架构,这也为后续产品的多元化发展奠定了基础;为了满足不同用户的需求,我们推出了SQLServer2008R2/2012/2014/2016Web/Standard/Enterprise等不同版本和版本的组合版本;为解决上云难的问题,推出了上云测评工具,以及针对不同版本和场景的上云解决方案全量备份数据上云SQLServer2008R2版本,全量备份数据上云SQLServer2012及以上,增量备份数据到cloudSQLServer2012及以上,SQLServer实例级数据库上云;为了提升用户体验,支持更多的特性,我们层提供了很多封装的存储过程。这里有些看似简单的功能,在外部安全、内部SQL镜像等因素的综合作用下,实现起来还是非常具有挑战性的;为了让专家服务更智能,更贴近每个用户,我们开发了SQLServerCloudDBA,集成了云端大量性能和空间问题的解决方案。其中,还有用户对读写分离的需求。每次遇到他们,我们都是先引到IaaS层,用ECS来实现。因为PaaS的时机还不成熟。具体原因与SQLServer目前的技术栈和云产品的结合密切相关。在这里我们也可以分享一下我们背后的一些思考。2.读写分离首先要明确我们讨论的读写分离是什么。MySQL的读写分离大部分都是使用中间层进行路由分析,基本可以对应用端透明。只有少数场景需要用户适应。SQLServer没有成熟的中间件产品。本质上就是TDS(TabularDataStream)没有完全开放的原因。想做是有办法的,但是投入的成本远大于收益。基于此,无论SQLServer采用何种技术实现读写分离,都需要针对应用进行一些适配。即使采用了AlwaysOn技术,链接驱动的参数配置也会有所不同,所以我们后面讨论的读写分离就是基于这个前提。3、技术选择我们比较了SQLServer的所有相关技术栈:其中数据安全、HA(HighAvailability)、DR(DisasterRecovery)和备库的可读性是我们最关心的。这里的HA是指原生技术本身是否支持自动HA。结合一些云产品,我们也有变不支持为支持的能力。数据安全和容灾时间基本由原有技术决定。备库是否可读是单一技术的描述,但一些技术的组合可以将不可读变为可读(如DatabaseMirroring+DatabaseSnapshots)。最后综合看TransactionalReplication和AlwaysOn,我们觉得有机会做读写分离,把技术商业化。那么我们分别来看一下这两种技术的对比:从原理上讲,Replication是逻辑复制,与AlwaysOn的物理复制相比,在性能、延迟、可靠性等方面都会有一定的差距。在产品的复杂性、可读性、可控性和易用性上,因为Replication过于灵活,很难控制到表和列的层面。不管是用户用还是我们做产品化,整体的复杂度都很高,所以我们最终选择了AlwaysOn。4.AlwaysOn技术AlwaysOn是一种原生支持HighAvailability和DisasterRecovery的技术。它分为FailoverClusterInstances(以下简称FCI)和AvailabilityGroups(以下简称AG)。FCI和AG的基础架构如下图所示:其中,FCIAG和普通版都依赖于WindowsServerFailoverClustering(以下简称WSFC)。区别在于FCI是ShareStorage,AG是ShareNothing;FCI是实例级同步,AG是DB级。那么很容易想到ShareNothing会有同步和异步的区别(类似于镜像技术),而两者的区别需要我们知道AlwaysOn的基本同步流程:首先,日志(Commit/LogBlockPrimary节点的Write)会从LogCache到磁盘,同时Primary节点的LogCapture也会将日志发送给所有其他Replica节点,对应节点的LogReceive线程也会flush将接收到的日志从LogCache写入磁盘,最后由RedoThread将这些日志应用到数据文件中。这里面还有一个步骤,就是在secondarysidelog时,如果primary节点等待这次返回的AcknowlegeCommit,那么就是同步模式;否则,如果初级端不等待次级端的返回,那么就是异步模式,两者的区别从这里展开。这是基本的同步流程,但是无论是AlwaysOn还是DatabaseMirroring,都有一种情况,就是如果Secondary端在同步模式下出现异常,Primary端没有收到自己的心跳,也没有收到这个AcknowlegeCommit,那么也不算写失败。因为一旦识别到Secondary异常,就不会等待这个ACK,而是退化成类似异步的模式,而是会把Secondary端的异常状态记录在基表中,通过相关视图暴露出来:sys.dm_hadr_database_replica_states,sys.database_mirroring出来,就是我们常见的NOTSYNCHRONIZING/Disconnect状态。这个时候就需要自动化运维系统或者DBA来做判断了。在从服务器修复并重新上线后,它将向主服务器报告日志结束(EOL)LSN,主服务器将在EOLLSN之后将所有加固的日志发送给它。一旦secondaryside开始接收这些日志并逐渐刷入日志文件,整个AG或者Mirroring相关的view都会将它们的状态标记为Synchronizing,表示正在赶上,直到LastHardened(LH)LSN到达master-slave一致状态。此时,它返回到同步模式。以前一直都是这样。直到SQLServer2017CU1引入了参数REQUIRED_SYNCHRONIZED_SECONDARIES_TO_COMMIT,参数名很长,但基本包含了它的作用。针对刚才的场景,Primary端可以等到Secondary节点重新上线同步后再提供服务。了解了AG同步、异步和FCI之后,我们总结一下我们的关注点:在实际的解决方案中,这些也可以结合起来,最终与阿里云产品集成,形成一个整体的解决方案。前面提到过,阿里云从2015年开始就在做类似的解决用户问题的方案,到最后完成PaaS,经历了三个版本。5、最新版本的云演进,我们以ECS、SSD云盘、OSS、VPC、SLB为基础;SQL技术方面,我们采用SQL+WSFC+AD。目前,该方法支持的版本也有很多,从12到17不等;验证方法可以是域控制器或证书。但有两个缺点:成本高。除了Primary和两个Secondary节点外,还有两个AD节点。毕竟我们要保证每一个环节的高可用;稳定性不够。网络抖动的情况很容易让WSFC判断异常,SQL端的DB也不可用。这是架构的第二个版本。与最新版本相比,我们使用HAVIP来解决监听器问题,去除AD,只使用证书进行验证,但是最小的资源开销降低到3。这个方案之前在阿里云上也用的比较多,但是和第一个一样解决方案,在网络稳定性上会有很多挑战,因为我们未来面临的场景不仅仅是同城跨可用区,还有更多的跨地域、海外场景,所以这个解决方案只能覆盖一些用户的需求,但这不是我们的最终解决方案。最终我们找到了第三种解决方案,去掉WSFC和AD,只关注基础云产品和SQL本身。最重要的是,与方案二相比,对网络抖动的敏感度会更低,更可控。至多在Primary端会有SendQueue的堆积。我们可以通过SQLServer相关的PerformanceCounter来监控,并进行一些修复。调整。但没有一种解决方案是完美的。可控性强的代价是,这种非集群、非域控的架构本身是不具备HADR能力的。熟悉WSFC的同学可以知道这一点。之前架构的HA依赖于WSFC,包括健康检查、资源管理、分布式元数据通知维护、故障转移,所以这个时候我们要自己解决这个问题。为此,我们也付出了很多努力,最终实现了一个支持AlwaysOn、无域控无集群的HA系统,以及不依赖Cluster的完全自主可控的HA系统。6.产品化最终产品架构如下。首先,会有2个同步节点作为主备节点,它们会尽可能分配在不同的可用区。其他只读节点默认是异步的,最多可以有7个只读节点;用户访问可以有三种链接:读写链接:会指向两个同步节点,我们的HA保证高可用;统一只读链接:根据用户需求设置,将指定的Replica节点按照一定的权重比例分配链接绑定在一起;单一只读链接:即每个只读节点都会提供一个单独的链接,这样用户也可以灵活配置。比如用户的APPServer在可用区A,那么可以直接访问可用区A的只读地址,避免通过统一只读路由到其他可用区。至此,SQLServerAlwaysOn已经在阿里云以PaaS的形式实现。当然,目前只支持最重要的功能,未来还有很多可以完善和丰富的地方。如果您有什么好的建议或者问题,欢迎您留言与我交流。
