这篇文章源于阅读任杰(ebay支付账务系统负责人)老师的《分布式金融架构》后的整理,也有部分个人的理解。专栏内容很高,作者结合了自己在金融领域的丰富实战经验,系统性地介绍了金融业务核心需求和相应的架构设计思路,建议大家学习一下。
扫码跨境支付流程
金融业务有很多种,按业务模式划分,包括交易类业务和信贷类业务两种。扫二维码支付属于交易类业务,从终端用户的角度来看,扫码由鉴权、支付和拉取状态三个步骤组成。
鉴权
用户在扫码支付前需要证明自己合法拥有银行卡,需要给开卡行提供 4 要素:姓名、身份证、银行卡号和手机号。验证通过后便可以开始支付流程。支付完成后用户可以通过轮询的方式异步获取支付状态。
交易
前面我们假设了这笔支付涉及到外汇交易,由于买家的和卖家使用的币种不同,就无法直接转账。这时候就需要第三方支付公司这个中间人来帮忙了。中间人角色要做 3 件事情:本币代收、外币交易、外币交易。
在第三方支付公司收到支付请求后,开始进行本币代收业务。由于账号设立的关系,需要进行跨行转账。此时清算中心和央行一起提供了跨行转账功能。跨行转账一般采用了日间交易、日终轧差结算的方式进行。轧差处理是金融机构应对支付流量的另一种架构设计,其本质是实时消息的批量处理。
第三方支付公司在完成本币代收业务之后,还要进行汇兑业务,按照交易量的大小,可以分为 C 端外汇零售业务和 B 端外汇批发业务两个部分。外汇交易是有成本的。第一个成本是时间成本。当天购买的外汇可能隔天才到账。另一个成本是交易成本。外汇交易一般会按照交易次数收费。因此为了节省成本,第三方支付公司通常会提前购买大量的外汇,用来应对日间的业务。只有当外汇储备下降到警戒线之后再做下一笔大额外汇的购买。
外币代付流程和本币代收流程在原则上是一样的。不同点在于外币代付的金额是美元,流出账号是第三方支付公司的美元账号。由于卖家的账号在卖家开户行,,第三方支付的美元账号在汇兑提供行,这时候需要走的是国际的清结算过程。
拉取状态
轮询是第三方支付和金融机构的主要对接方式,这是因为金融机构每天会面对大量的用户资金操作,这些操作的时间和频率有很大的偶然性。为了应对用户操作的峰值情况,金融机构普遍通过异步消息处理的架构来对极端流量进行削峰填谷。如果流量突然增大,异步消息架构会缓存所有请求,慢慢处理。这样就能避免核心金融系统超载。异步消息架构的结果就是用户不会及时得到处理结果,需要自己不断地去查询处理情况。
支付业务核心组件
在支付业务中最核心的概念是信息流与资金流分离,那什么是信息流和资金流呢?用一句话来概括,信息流指的是想象中钱的流转过程,资金流指的是钱的实际流转过程。
电商公司支付架构
- 业务系统:负责生成交易订单和支付订单;
- 账务系统:负责维护用户账户情况;
- 支付网关:负责处理支付订单,具备将内部和外部资产两种操作,分发给不同的资产处理组件的路由能力;
- 核算系统:晚上与第三方机构对白天所有交互的明细进行核算,同时保证账务系统与业务系统之间的一致性。
- 金融网关:对接第三方支付公司,使得外部资产管理系统可以完成银行卡转账业务;金融网关主要是实现二进制协议的对接,比如证书签名、加解密、协议传输、数据校验等。
第三方支付系统
备付金资金池:第三方支付公司在调用银行接口的时候会产生费用,利用备付金资金池可以减少一些交易费用,同时还能提高用户体验。一般有了支付牌照之后,第三方公司才可以建立用户的备付金资金池。当把资金池分散在多家银行之后,第三方支付公司就不再受制于单独某家银行。这样利用不同银行的费率情况可进一步降低运营成本。
清算中心:第三方支付公司对分布在不同银行的资金池之间的转账交易进行清结算工作。
跨银行备付金和清算中心合在一起后,第三方支付机构就具备了跨行清算的能力。由于这种业务模式不容易监管,容易出现洗钱等非法行为,国家已经逐步取消了这种资金管理模式。
金融业务技术选型
信贷类业务
信贷业务俗称放贷,传统的银行主要从事的就是这个业务。信贷类业务的表现形式有很多,比如有面向企业的贷款,或者给你的房贷,以及 P2P,花呗、借呗、白条等等。
传统信贷业务
传统信贷类业务利用了哪些信息不对称来挣钱,因此核心竞争力变成了怎么才能更好地收集和处理数据,这就是大数据能发挥价值的地方。对于系统架构来说,信贷业务的特点是交易频率低,而且用户评级在短时间内不会发生大的变化,因此整个系统架构不需要实时组件,常用的批处理、大数据处理框架都能很好地发挥作用。
资产证券化
银行定息存折是可以抵押给银行然后再贷款的,这个过程就是资产证券化。2008 年发生的次贷危机就是用个人的房贷来抵押贷款。简单的抵押赚不了多少钱,所以有一些聪明人把一大堆房贷打个大包,然后按照信用评级拆分成几个小包。类似的小包还可以堆在一起,然后再继续拆分。最后再将拆分好的小包卖给投资人。
技术选型。资产证券化的定价过程对系统有两个挑战,一个挑战是计算复杂。贷款可能违约,这个违约的大小是用信用评级来衡量的,所以违约率其实是一个数学上的概率。把不同资产放在一起,打包后再拆分的过程,从数学上来看就是用一组随机变量生成一个新的随机变量。另一个挑战是数据量大。资产证券化到一定程度之后就算不出来数学公式了,只能通过暴力求解的方式来穷举所有可能的场景,这就涉及到如何保证分布式计算的正确性。
交易类业务
在交易所内的交易叫作场内交易,交易的场所就是交易所。一级市场:公司股东之间的私下交易;二级市场:公司的股票在股票交易所内的交易。
场内交易
_从交易所维度来看_,一级市场的信息不对称主要体现在如何匹配大额股票的买家和卖家。投资银行解决信息不对称的方式是通过公司和自己的人脉来撮合买卖双方。由于解决方案是靠人而不是靠技术,所以这一阶段对信息系统要求不高。二级市场是个公开市场,靠大量的交易来解决价格信息不对称问题,而不是靠人脉关系。这时候就对信息系统有很高的要求信息沟通得越快,就越能发现资产的合理价格。所以股票交易强调交易的速度,也就是系统延时。
技术选型。对开发人员来说,股票交易所是一个秒杀系统,只不过和电商秒杀的区别在于股票交易所每时每刻都在秒杀,所以股票交易所需要有一个极低延时、极高吞吐量的系统架构。互联网方案(比如分库分表、缓存、最终一致性)都是靠牺牲延时来换取流量,对于股票交易所来说,高延时是完全不可以接受的。
股票交易所实现低延迟、高吞吐的方案:用硬件实现业务逻辑,譬如 FPGA 来实现。理论上硬件能实现和所有软件一样的功能,但是硬件研发成本高,而且非常耗时。注:交易所业务逻辑比较简单,其主要功能是撮合买方和卖方。交易所在系统内维护了还没有成交的卖方订单和买方订单。当一个新的订单进来的时候,交易所会查看能不能成交。如果不能成交就等待下一笔订单。这个撮合逻辑非常简单直白,示意图如下:
_从交易所用户角度来看_,有一些金融机构会故意增加信息不对称(如拆单服务),而另一些金融机构则在努力发现和消除这些信息不对称。投资银行赚钱的方式是通过信息技术来造成信息不对称,做高频交易的对冲基金是另一类通过发现和消除信息不对称来赚钱的金融机构。他们的核心竞争力就是极低的系统延时。当延时高的时候,股票体现的是宏观规律,比如你会看公司的基本面,或者猜是不是庄家在出货。但是当延时低的时候,股票体现的是统计规律。
技术选型。机构用户要求系统的消息处理时间在毫秒和微秒之间。编程语言的选择,一般来说 C 是首选,核心代码用汇编语言实现。要求不高的地方用 C++ 也可以。至于互联网常见的编程语言,比如 Java、Go、Python、Javascript 等,都不适合。软件架构的选择,不会使用 SOA 或微服务,机构用户系统会用单个进程来完成所有的事情,最好不要有网络开销。
场外交易
绝大部分的金融交易都发生在交易所外,也叫场外交易。场外交易的金融产品都存在共性,比如说它们肯定都跟钱有关。这些共性可以进一步提炼出来,从而有希望搭建一个金融产品的统一定价平台。这个抽象总结的方法就是领域驱动设计。
金融业务统一模型
领域驱动设计
顾名思义,领域驱动设计(Domain Driven Design,简称 DDD)指的是针对特定领域进行定制化的设计。领域驱动设计是战略上的思路,而不是战术上的实操,解决的是复杂问题。具体来说,适合使用领域驱动设计的系统需要具备这些特点:1、系统组件足够多,2、业务逻辑足够复杂,3、软件生命周期长。金融系统就很适合用 DDD 做顶层设计,设计的两个核心原则是:追求投资回报比,以及长期优化。
领域驱动设计首先解决了人的问题,领域驱动设计建议软件的所有参与方之间能以小组的形式进行直接沟通,而不是采用传统的层级式沟通方式。开发要懂业务,业务方和产品也要懂技术。沟通的结果是形成一个大家都能认同和理解的领域语言。领域驱动设计带来了文化的转变,包括:提高了决策的速度、打破了部门壁垒、弱化了产品经理的角色。
理顺了人之后,我们就可以解决事情了。领域驱动设计将复杂的系统组件分为三大领域:核心领域、通用领域以及支持型领域。核心领域与金融公司的核心竞争力有直接关系,判断其是否属于核心业务的依据是它是否给公司带来行业内的竞争优势。通用领域可以跨不同行业,要尽量采购相关服务或者产品,而不是自己研发,支持型领域负责支持核心领域,跨行业的可能性较低。
统一金融模型设计
要从建模逻辑和生命周期两个方面来看。
建模逻辑分为三个大的方向:实体、值对象和领域服务。
- 实体是有唯一标识的业务实体,有生命周期,有状态,有业务逻辑;
- 值对象没有唯一标识符,是通过自己内部属性来判断唯一性,也没有生命周期,通常作为实体的属性或者状态存在;
- 领域服务只包含业务逻辑,不包含任何状态,它通过操作实体和值对象来实现最终的功能。
金融行业的领域服务有一些独有的特性。首先,领域服务不附属于任何一个实体或者值对象。它自身独立存在。其次,金融产品的领域服务有一个设计原则是。无状态指的是它内部没有维护全局状态,整个计算过程也不能有任何随机性。请注意这是金融行业的设计原则,而不是所有行业都有这个要求。因为金融行业对正确性要求非常高,做任何计算都建议不要出现不确定性。这也是为什么金融系统架构普遍都是不可变架构(Immutable Architecture)。
通常生命周期管理不是以单个实体为粒度进行管理的,生命周期管理也分为三个大的方向:聚合、工厂和仓库。
- 聚合将紧密相关的实体和值对象组合成一个原子单元。外界只能直接访问这个原子单元的根结点,不能直接访问内部节点。聚合除了定义影响力边界以外,还同时定义了存储边界,聚合里面所有内容需要在一个数据库事务内操作。
- 工厂负责生成聚合,对象的使用由领域服务来负责,而创建由工厂来负责(和设计模式里的工厂作用完全一样)。
- 仓库负责将聚合序列化和反序列化,起到防腐化层(Anti-corruption Layer)的作用。防腐化指的是不让外部协议的变化来入侵内部协议,所以防腐化指的是不让外部协议的变化来入侵内部协议。
补充金融业务要点
POJO 对象和领域模型
POJO 的问题在于它是二进制表现形式,缺乏了对象(Object)的行为。在缺乏的行为中,最重要的就是逻辑校验的能力。所以 POJO 的使用方需要重构所有的业务验证逻辑,这相当于从二进制数据中反编译出原来的业务行为。大公司会有很多不同类型的业务数据,这就会导致很容易出现反编译的错误,选择用 POJO 的话,效率就没有之前那么高了。
对于金融公司来说,对正确性要求非常高,因此会选择在初期就使用领域模型。
外汇支付和系统架构
外汇支付具体过程:第三方支付公司从外汇交易商那里提前用人民币购买美元,并将美元存放至美元资金池内,用户用人民币购买等值美元物品时,用户先将这人民币转给第三方支付公司的人民币账户。第三方支付公司再从自己的美元账户内转等值美金给卖家。
外汇系统是利用自有资金池做交易,属于内部资产管理,因此和第三方支付公司的资金池处理非常类似,多数组件也能复用。
- 汇率查询:提供当前可交易汇率给跨境电商的支付页面。
- 清算中心:减少资金流的交易笔数,进而节省外汇交易成本。