云原生(Cloud-Native)到底是什么?这个问题一直很难定义。CNCF技术监督委员会最近通过投票确定了其官方定义。如何使其弹性可扩展、稳定高可用、敏捷易维护等特性应用到现有创新场景?
今天我们来剧透一下 “海量数据访问” 话题之一:金融级数据高并发访问的挑战
概述
随着近年来移动支付、普惠金融的兴起 ,再加上层出不穷的业务创新,比如秒杀、大促、团购等等,这些新的模式对传统架构形成了不小的冲击。
这个过程中,对数据访问的性能、容量、稳定性、高可用容灾等方面也提出了更高的要求。在这些高并发访问的场景下,分布式架构逐渐成为趋势,但同时也带来了新的问题:业务实现复杂度加大、跨服务/跨分库的数据一致性问题、容灾复杂度上升、高可用实现难度加大、运维复杂度上升、下游链路同步变复杂等等。
这些都需要我们重新思考合适的解决方案。
挑战 1 :性能容量的瓶颈
集中式架构下,单个数据库的性能、容量瓶颈可以通过 scale-up 的方式解决,但是当访问量并发激增到一定量级,单纯的数据库 scale-up 已经不能完全解决了,而且成本非常高昂。
应对方式:
业界常见的做法是在应用层实现数据服务的 scale-out 能力,不再受限于数据库的瓶颈:
垂直拆分:通过系统垂直拆分进一步减少单库压力,提升系统容量。
水平拆分:流水型及状态型数据垂直拆分后,如果单库容量仍然不够,可以基于某一维度(比如用户ID的某2位做hash)进行分库分表拆分,该拆分维度建议在全公司业务内保持一致,这样对后续做机房单元化有很大帮助。
读写分离:偏静态类数据,读多写少并且可以容忍一定数据延迟的情况下,可以使用读写分离加缓存的策略。
数据拆分的优势很多,提升存储容量、性能、连接数容量、为单元化铺路等等,具体拆分的思路以及相关问题可以参考《支付系统如何进行分布式改造》
挑战 2 :更高的稳定性要求
稳定性是一个绕不开的话题,当业务体量达到一定规模,一个很小的稳定性问题,对用户造成的影响可能都是巨大的。
我们也统计过,大部分故障都来自人为变更或者对系统评估不足,而非硬件故障;这个变更包括运维变更、业务代码逻辑变更等。公司在发展,变更、稳定性两条腿都要往前走,所以迫使我们去思考更加细致全面的方案来为业务稳定性保驾护航。
如何将变更的影响面降到最小,甚至只是某一个用户?有没有机制来提前确保变更一定能成功?有没有比较通用的功能?所有的考虑都是为了尽量避免人为故障的产生。
针对常见的变更需求,我们在数据层也提炼了不少保障能力,下面分享一个比较有代表性的。
应对方案举例:
数据链路容量验证:SQL 压测,让你对容量胸有成竹
业务诉求:我扩容后的应用服务器、数据库集群真的能扛过大促业务吗?有没有办法提前精准的验证一下?到大促来临时如果数据库容量有问题,一切都晚了
SQL 压测能力主要是用来验证系统数据层容量是否满足期望。当业务需要为即将来临的活动做准备(大促、秒杀等),或者制定未来几年的系统容量规划,亦或准备升级/更换 DB 等,SQL 压测能力可以很好的帮助业务链路来精准验证。
比如下个月的活动预计峰值是1万笔订单/秒,这个月系统扩容就绪后,就可以通过SQL 压测功能提前验证相关系统容量。这时候可以通过网络入口的压力机模拟业务压测流量慢慢放大到 1 万笔/秒,观察线上 App 服务器及 DB 情况,如果有问题及时解决,将所有风险提前规避掉,在活动来临时就可以做到胸有成竹,“喝着咖啡过大促”。
SQL 压测其实 DB 层也有不少工具可以来实现,比如 SQL Replay 等,但在中间件层来实现,还是有其优势的:
非常贴近业务活动真实链路情况,业务可以针对性的放大活动相关的服务进行压测;DB 层做的话,很难针对活动 SQL 及数据模型进行压力放大
因为压力是从上游发起,所以可以验证到整个 App 服务器到 DB 链路的容量,这个DB 层工具很难做到
一个完整的压测链路功能涉及到网络入口层的业务压力模拟到后面压测流量自动打标、DB 部署等准备,其中的细节很多,后续会有专门的文章来完整的讲解 全链路压测的思路。数据层实现大体思路如下:
流量标记识别:针对压测流量 SQL 打上特定标记,比如 SQL 加上类似/*+ TestLoad */ Hint 前缀,或者通过线程变量传递标记信息(TestLoad=Y/N),数据路由层识别该标记。
业务压测状态判断:这一步是辅助可选步骤,会判断业务是否开启了压测模式,跟上一步的判断形成 double check,目的是防止第一步误打标。
数据源选择:根据是否压测 SQL,选取正确的物理库连接并发送 SQL,这里 业务 DB 跟 压测 DB 底层可以是同一个也可以分开;保险起见,为了防止压测数据污染业务表,以及方便运维管理,压测表名跟业务表名一般会不一样,但存在一定关系,比如业务表是 order,压测表就是 order_t。
分库配置:这里进一步扩展了分库配置模型,做成弹性架构,提炼出分组(Group)的概念,一个分组下可以有多个DB 供路由选择,具体使用哪个 DB 由压测库开关或读写权重来控制等开关来控制。
挑战 3 :追求极致的高可用容灾
数据是每个企业最宝贵的财富,特别是金融类企业。高可用容灾方案也一直在演进过程中,单机容灾、同城容灾、异地容灾等等,但受限于CAP理论,还有高性能的要求,完美的异地容灾是很难做的,但有没有思路来无限接近呢?
容灾能力主要有两个指标:
RTO,Recovery Time Objective,恢复时间目标。表示能容忍的从故障发生到系统恢复正常运转的时间,这个时间越短,容灾要求越高。
RPO,Recovery Point Objective,数据恢复点目标。表示能容忍故障造成过去多长时间的数据丢失,RPO 为 0 表示不允许数据丢失。
应对方案: IOE 时代的切换方案
以前的集中式 IOE 架构下,应用对数据的高可用方案感知度很低,单机容灾 基本靠数据库跟存储的能力,比如以前很流行的 IBM HACMP 方案、Oracle RAC 方案,Oracle DataGuard 最大保护模式(主备之间强同步,性能受限)、日志共享存储方案等等,都能够保证单机故障不丢数据。但是如果再加上高性能、低成本的要求,估计只有日志共享存储方案 才能满足需求了。
但日志共享存储方案 有个很大的问题是 RTO 的时间比较长,不过谁让它成本比较低呢,RTO 我们可以再想一些办法来优化。
以 Oracle DataGuard 最大性能模式(主备之间异步复制) + redo日志放共享存储方案的主备切换为例。
为了保障数据一致性,DBA 的操作往往需要 5~10 分钟的时间,如果主库遇到硬件故障 Down 机,为了保障数据不丢,切换时间会更长,最快也要 15 分钟左右。这还是光做操作的时间,还不包括发现故障、打开电脑上线的时间,所以以前的容灾体系对运维提出了很高的要求,稍不留神,可用率就破线了。虽然后续可以做更多的故障自动探测 (Auto Failure Detector) 、自动切换工具等等,但时间总归还是比较长,数据库的切换机制摆在那。
另外,这种方案也只能接单机故障,如果主机房出现故障,网络瞬间全断,备机房还是有可能丢一部分数据。
上面说的方案,部署架构图类似如下,其中主备库服务器可用性已经通过切换方案来弱化了,所以可以把 IBM 机器换成更加经济的 PC 服务器,进一步降低成本:
应对方案:业务 Failover 方案
SOA 化之后,核心的服务都独立了出来,完全底层的容灾方案已经满足不了业务的可用性要求,特别是在 RTO 跟跨机房容灾这 2 个方面。这时候应用层高可用方案开始百花齐放,根据不同的业务特性、数据特性,设计了多种快速 Failover 的方案。
思路概括起来就是:借鉴 BASE 理论,为了实现核心业务快速恢复,可以牺牲一定的一致性,只保证数据最终一致;同时采取一些措施保证业务不会读到脏数据,也保证影响面仅控制在数据未完全同步的那部分用户。
基于应用层的快速 Failover 方案解决了 RTO 过长的痛点,服务可以快速恢复,交易核心业务原来需要 DBA 10分钟主备切换完才能提供服务,现在直接推送Failover流量到新的空库,业务秒级就可以恢复;同时结合机房级、城市级切流方案,可以满足跨机房、跨城市的容灾,这部分不再详细描述,可以参考《分布式系统数据层设计模式》。
虽然从数据库角度看 RPO 并没有做到真正意义上的 0,但是我们通过对业务的理解,对数据的理解,可以做到无限接近 0,之间的差距数据只保证最终一致性即可。换个角度来讲,从业务角度看 RPO,其实已经是 0 了,因为并没有用户能够访问到脏数据。
这些都是根据业务特性来定制的高可用方案,所以对应用代码侵入还是挺大的,那有没有更为通用的方案呢?甚至是业务不用做任何改造的方案呢?下一篇我们继续讨论。
相关链接:https://www.cloud.alipay.com/products/DBP
欢迎大家共同打造 SOFAStack https://github.com/alipay
公众号:金融级分布式架构(Antfin_SOFA)
网友评论