支付核心系统设计:Airbnb的分布式事务方案简介

导读:微服务架构下的支付系统,由于其需要在性能和一致性之间做很多权衡,带来设计和实现的复杂性。Airbnb的支付系统需要对接全球很多个国家的支付系统,因此带来很大的复杂性。本文详细论述了Airbnb如何使用分布式事务的相关技术来保证支付系统的数据一致性和性能,十分值得一读。


过去几年中,Airbnb一直在将其基础架构迁移到SOA。相比单体应用,SOA提供了许多优势,例如支持开发人员专业化和加速迭代的能力。然而,这也对计费和支付程序提出了挑战,因为SOA使维护数据完整性变得更加困难。对服务API的调用,该服务对下游服务进行进一步的API调用,其中每个服务改变状态都可能具有副作用,等同于执行复杂的分布式事务。

为了确保所有服务之间的数据一致性,可以使用两阶段提交之类的协议。如果不用这样的协议,数据一致性就难以保证。在分布式系统中请求不可避免地会失败(连接会在某些时候丢失并超时,尤其是对于包含多个网络请求的事务。

分布式系统中使用三种不同的常用技术来实现最终的一致性:读修复,写修复和异步修复。每种方法各有利弊。三种方式在我们的支付系统中都有使用。

异步修复通过服务器负责运行数据一致性检查来实现,例如表扫描,lambda函数和cron job。此外,从服务器到客户端的异步通知广泛用于支付行业,以保持客户端的一致性。异步修复以及通知可以与读写修复技术结合使用,提供第二道防线,并在解决方案复杂性方面起到作用。

本文中描述的解决方案使用了写修复,其中从客户端到服务器的每次写入调用都尝试修复不一致状态。写修复要求客户端更加智能(稍后我们将对此进行扩展讨论),并允许重复发出相同的请求,而不必维护状态(除了重试)。因此,客户端可以按自己的需求来达到最终的一致性,从而使他们能够控制用户体验。在实现写修复时,幂等性是一个非常重要的属性。


什么是幂等?


API请求具有幂等性即客户端可以重复进行相同的调用,结果将是相同的。换句话说,发出多个相同的请求应该与发出单个请求具有相同的效果。

这种技术通常用于涉及资金流动的计费和支付系统,即支付请求必须完全处理一次(也称为“确切一次交付”)。重要的是,如果多次调用移动资金操作,系统最多只能移动一次资金。这对Airbnb Payments API至关重要,以避免多次支付。

幂等性允许来自客户端的多个相同请求使用API的自动重试机制来达到最终一致性。这种方式在具有幂等性的客户端 - 服务器中是常见的,并且在我们的系统中也是如此。

下图说明了重复请求和理想幂等行为的简单场景。无论收费多少,客户最多支付一次费用。

640?wx_fmt=png


问题描述

保证我们的支付系统最终的一致性至关重要。幂等性是在分布式系统中实现这一点的理想机制。在SOA世界中,我们将不可避免地遇到问题。例如,假如服务没有响应,客户端将如何恢复?如果Response丢失或客户超时怎么办?如果竞争条件导致用户点击“预订”两次呢?我们的需求包括:

  • 我们需要一个通用但可配置的幂等解决方案,而不是实现针对特定用例的自定义解决方案,以便在Airbnb的各种支付服务中使用。

  • 虽然正在迭代基于SOA的支付产品,但我们无法在数据一致性上妥协。

  • 我们需要超低延迟,因此构建单独的幂等服务不能满足延迟要求。最重要的是,该服务将遇到上述问题。

  • 随着Airbnb使用SOA扩展其工程组织,让每个开发人员专注于数据完整性和最终的一致性是非常低效的。我们希望业务开发免受这些麻烦,保证他们能够专注于产品开发并更快地进行迭代。


此外,代码可读性,可测试性和故障排除能力的相当大的权衡被认为是非主导因素。


解决方案


我们希望能够唯一地识别每个请求。此外,我们需要准确跟踪和管理特定请求在其生命周期中的位置。

我们在多种支付服务中实施并使用了“Orpheus”,这是一种通用的幂等库。Orpheus是传说中的希腊神话英雄。

我们选择了实现幂等库作为解决方案,因为它提供低延迟,同时仍然提供高速变更的产品代码和低速变更的系统管理代码之间的隔离。在高层次上,它包含以下:

  • 幂等key被传递到框架中,表示单个幂等请求

  • 始终从主数据库读取和写入(为了一致性)幂等信息表

  • 通过使用Java lambda组合数据库事务,确保原子性

  • 错误被分类为“可重试”或“不可重试”


接下来我们将详细说明具有幂等性保证的复杂分布式系统如何能够自我修复并达到最终一致。我们还将介绍一些该方案应该注意的设计权衡和带来的额外的复杂性。


最小化数据库提交


幂等系统的关键要求之一是只产生两个结果,即成功或失败,具有一致性。否则,数据有偏差可能导致数小时排查错误时间和付款出问题。由于数据库提供ACID属性,因此数据库事务可以有效地用于原子写入,确保一致性。一次数据库提交可以保证其作为一个单元的一致性。

Orpheus假设每个标准API请求都分为三个不同的阶段:Pre-RPC,RPC和Post-RPC。

“RPC”是指客户端向远程服务器发出请求并等待该服务器响应的过程。在支付API的上下文中,我们将RPC称为对下游服务的请求,其可以包括外部支付服务和收单银行等。简而言之,如下是每个阶段发生的事情:

  • Pre-RPC:付款请求的详细信息记录在数据库中。

  • RPC:请求通过网络对外部服务进行实时处理,并收到响应。这是一个执行幂等计算或RPC的过程(例如,如果是重试尝试,则首先查询事务状态)。

  • Post-RPC:来自外部服务的响应的详细信息记录在数据库中,包括其是否成功以及错误请求是否可重试。


为了保持数据完整性,我们遵循两个基本规则:

  • 在Pre-RPC和Post-RPC阶段,没有远程服务交互

  • RPC阶段中没有数据库交互


我们希望避免将网络调用与数据库操作混在一起。在pre-RPC和post-RPC阶段网络调用(RPC)易受攻击的,并可能导致连接池快速

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值