逃不掉的双十一 可怕的分布式架构隐患
在刚刚过去的双十一,淘宝怒斩 571 亿交易额,成为年度的最大赢家。负责本次双十一技术服务的蚂蚁金服集团表示:双十一的交易峰值已经达到 285 万笔/分钟,相比去年双十一期间 79 万笔/分钟的交易峰值,今年系统的支撑能力达到了去年 3 倍以上,用户整体支付体验相比去年也顺畅不了不少。从网友反馈的实际体验来说,今年双十一相比往年的确有了不小的提升,页面打开的速度更快了,支付等待时间更短了,优惠力度更给力了……但是有没有问题?有,而且这些问题从某种意义上讲则是致命的。
抽风的支付宝,多次付款的迷局
11 月 11 日凌晨 1 点,多家电商平台反馈称,支付宝出现支付故障,用户无法正常支付。这也不是双十一第一次出现类似的故障。去年双 11 开始后,由于订单量瞬间激增,就曾爆发多家网银无法通过支付宝支付的情况。今年双 11 在手机支付宝上也一度出现瘫痪,即使在阿里巴巴的直播大厅中,也无法支付成功。
在笔者看来,即便是采用了云计算的全新方式,支付宝的使用弊端依然是存在的,而且这些弊端在系统架构层面一直是淘宝解决不了的死结,这就是系统架构层面的硬伤——分布式系统的数据一致性。而要解释这个问题,还要从淘宝主张的“去 IOE”说起。
简单、有效的淘宝的分布式架构
2008 年,从微软亚洲技术研究院离职来到阿里巴巴任首席架构师的王坚提出“去 IOE”的技术路线,即以廉价的 PC 服务器替代小型机,以基于开源的 MySQL 自研数据库替代 Oracle 数据库,用低端存储取代高端存储设备,阿里巴巴的交易系统架构进行了重构,根据业务和对象的不同,统一集中的数据库被拆分成了无数的耦合度较小的数据库。显然在这种架构下,随着业务的发展,可以增加新的数据库,也可以扩展已有的数据库,系统的扩展性和整体拥有成本非常好。
多年来的市场表现证明,分布式架构有效解决了淘宝海量数据高并发、高增长的问题,对于淘宝这种简单事务为主的 C2C 的业务模式来说也最适合。与此同时,在淘宝的系统架构中也秉承了扩展性高于一切、系统可用性高于一致性与适当放宽一致性约束等原则。对于绝大多数应用场景来说,这种分布式系统是合适的、高效的。如果不是出现双十一这种前无古人、全球罕见的大规模交易,分布式系统堪称 C2C 业务的完美形态。
问题正是出现在“分布式”这种特点中。按照美国著名科学家 Eric Brewer 在 2000 年提出的理论,当技术架构从集中式架构向分布式架构演进,会遇到 “CAP 定律”的瓶颈。 CAP 说明一个数据处理系统不能同时满足一致性,可用性和分区容错性这三个需求,最多只能同时满足两个。
一致性(Consistency):任何一个读操作总是能读取到之前完成的写操作结果,也就是在分布式环境中,多点的数据是一致的。
可用性(Availability):每一个操作总是能够在确定的时间内返回,也就是系统随时都是可用的。
分区容忍性(Partition Tolerance): 在出现网络分区(比如断网)的情况下,分离的系统也能正常运行。
正如我们刚刚提到的,淘宝在系统架构中选择了扩展性与可用性,放弃了一致性,这依然符合 “CAP 定律”的观点,意识到这一点的淘宝也采用基于 MySQL 的分布式架构能够完美的解决掉高并发用户访问的难题。
分布式系统的软肋——数据一致性
我们通过一个交易模型可以更好的解释这个问题。例如,一件商品有 100 个库存,而在同时有 130 个人在进行抢购的时候,集中式架构在完成买家付款这个业务操作时候系统需要做 6 个步骤:
- 启动事务,通过数据库锁等方式保证事务中的数据修改的一致性
- 更改买家支付宝金额
- 更改卖家支付宝金额
- 修改订单已付款状态
- 修改卖家货物数量信息
- 提交事务,保证数据全部更新
在集中式模型下,数据库和中间件均采用单线程模式处理业务,因此以上 4 个步骤的修改是同步的,因此如果支付宝接收到买家的付款以后,数据库事务处理将保证 4 个步骤的数据修改的一致性,即使该事务出现因为系统问题失败了,系统将同步退回到执行事务以前的状态。因此及时出现页面提交失败而重新刷新的时候,维护系统能够很方便查出买家付款但没有修改状态的问题,通过重新执行上述流程就可更新系统状态,因此不会出现重复付款的情况。另外在完成该数据库事务操作中的几毫秒中,卖家的货物数量会暂时被锁住,其他买家在这个时间段内无法修改卖家货物数量信息这个字段,因此也不存在超售的情况。
但在分布式模型下,数据库采用分布式的和数据库读写分离,也就是买家库、卖家库、订单库、支付宝账户库等均是完全物理分离的数据库,而为了提高并发访问的效率,每个库都由多台镜像数据库组成,同时为了消除读写瓶颈,每个数据库的数据只保存一部分数据,由上层应用来进行复杂的系统调度。在执行事务中的每一个步骤都是通过异步方式来完成的。
隔日退款——马云真不是为了凑成交额
昨天在跟几个业内朋友吃饭的时候,有人提到本次双十一期间,特别是从 11 日零点到 11 日 24 点这段时间内,用户是不能得到退款的,当时便有人戏称马云为了突破去年的成交额“禁止退款”。但事实上,且不说马云是不是需要通过这种方式实现成交额的激增,单看淘宝在系统架构上的设计,在如此大规模并发的请求下,退款将是一件非常困难的事情。
当完成银联支付的时候,修改订单已付款状态这个步骤出现了瓶颈,在理论设计需要在秒级修改的状态在 1 个小时内都没有更新,因此淘宝页面就重复提示买家需要支付货款,这样就为整个业务引入了“脏数据”,出现的货款与订单的重复关联,而这种错误理论上是不应该出现在正常的业务逻辑中的,因此要从系统中找回多余的付款将十分的麻烦,这也就是为什么支付宝必须在当天关闭退款申请,需要等高峰期过后通过系统维护将多余的付款退回。同时由于订单修改状态迟迟不更新,导致库存在买家完成采购付款依然没法正常扣除,从而导致“超售”的情形发生。
去 IOE,并不是去掉“宰牛刀”
记得当年淘宝大规模宣布“去 IOE”时,业内对于阿里的技术能力和 IT 视野都给予了充分的肯定。即便是到了现在,去 IOE 依然被证明是淘宝正确的举措。以技术能力而言,淘宝具备了世界顶尖的系统开发、运营和维护能力,丝毫不逊色于国外的 Google 和永远打不开的 Facebook。而且从业务模式来说,C2C 对于业务的安全性并没有苛刻的要求,从成本和应用的角度考虑,小型机抑或大型机的确是“宰牛刀”。
但正是从淘宝开始,去 IOE 似乎成为了一种行业的趋势,并大有蔓延之势。想想以淘宝的技术能力尚有每年双十一的支付困境,其他企业如何能够真正实现系统与业务的安枕无忧?想想每到春运便被吐槽无数的 12306,想想如果是在电信、银行这样的关键系统中出现支付问题,其影响与后果都将是耸人听闻。
有道是”术业有专攻“,没有哪种架构是万能的,分布式也不是万能的。双十一是一面照妖镜,让我们看到分布式系统的强大,也看到集中式系统的稳健。就是你有勇气决定进行分布式的改造,风险、技术门槛、后期的运维,估计也只有像阿里才能创造这样的神话。