雪球旗下蛋卷基金交易系统演进

avatar
@雪球财经

图片

雪球在2016年初上线基金交易,开发了独立App——蛋卷基金(后续简称“蛋卷”)。2016年5月,上线第一款白盒策略(策略细节、调仓算法完全公开)组合,获得了市场了一致认可,并在智能投顾方面引起了一阵风潮。至2018年初,蛋卷共支持4000余只基金销售,包括:货币基金、券商资管、债券型、混合型、股票型等;同时,在基金公司提供策略的基础上,实现了近20个白盒策略,包括轮动类、配置类、生命周期类、海外资产类等。

在2年的时间中,蛋卷基金交易系统从无到有、从使用第三方到使用自研系统、从功能单一到功能丰富,其中经历了一系列的改造、升级、重构,并在用户无感知的情况下,迁移到新系统,实现了一个大的飞跃。

| 业务介绍

基金交易体系与我们日常使用的电商交易有很多类似的地方。在基金交易系统中,基金是可售商品,用户交易流程与电商也类似,用户需要身份认证、绑卡、支付,然后购买相关基金产品。后端资金处理类似,涉及资金的清算和划转。

因此,在整个体系中,存在2个核心流程:一个是业务流,即:交易的产生,买卖行为等;另一个是资金流,即:钱从哪儿来,应该到哪儿去。2个核心流程彼此独立,但是又相互关联:业务是否生效,需要由资金确认,资金不到位业务需要作废;资金的清算、划转给谁以业务流为基础。

基金交易时间以一个T日为基础(一般为工作日,前一日15:00到后一日15:00为一个T日)

基金申购业务流,如图:

  1. 用户T日发起申购,蛋卷到第三方支付完成扣款

  2. T+1日基金公司会确认申购是否成功,同时确认基金份额

图片

基金申购资金流:

  1. 用户T日申购,T+1日资金从支付机构划转给蛋卷的监管银行

  2. T+1日,蛋卷的监管银行把资金划转给基金公司

  3. 在资金流中,监管银行负责资金监管

图片

以上,为一个典型的基金申购业务的业务流和资金流,对于一个基金交易系统,用户申请处理、第三方扣款、资金清算为核心功能。

| 交易系统 1.0

蛋卷最早使用的是第三方的基金交易系统,并在之上通过API封装和直接数据库调用的方式,如图:

图片

在以上架构中,第三方交易系统对于蛋卷而言是一个完全不可见的黑盒子,其中有一些问题持续困扰我们:

  1. 核心系统不可控。作为整个系统最核心的部分,蛋卷自己确无法控制,这意味着巨大的风险。交易数据我们可以通过数据库查到,但是整个系统数据的逻辑关系、外部对接、内部模块关系等我们完全不可知。

  2. 日常问题解决困难。由于系统日常需要维护,但是因为蛋卷不知道核心流程和实现,需要第三方人员配合,在处理效率上存在问题。有些问题(可能是BUG),由于现场人员经验限制,虽然影响长期存在,但持续无法解决,需要第三方内部协调。

  3. 升级/维护困难。整个第三方系统是构建在数据库基础上,业务严重依赖数据库。交易系统升级意味着数据库需要升级,意味着停机!!!升级停机对一个互联网应用而言,是很难接受的。如果升级失败、回滚,则意味着数据库要回滚,风险巨大。

  4. 新功能开发慢。由于第三方维护交易系统,涉及交易部分改造需要第三方支持。其中需求的沟通、开发、测试,过程漫长,对于一个快速迭代的产品而言,依然无法接受。

基于以上问题,蛋卷决定开发自己的交易系统。

| 交易系统 2.0

要开发自己的交易系统,面临2个问题:第一,是否可行?第二,如何迁移原有用户?

整个基金交易系统依赖大量外部系统:第三方支付、监管行、深证通(TA),这些第三方系统都是生产环境,大部分没有测试环境,即便有测试环境,也不支持具体测试用例的构造。另外,基金交易系统中,全平台是相互依赖的,如果T日有任何一家基金销售机构数据未上传,整个系统都需要等待。基于以上,如果我们想开发好一个交易系统,再在某个时间点全量上线,基本是不可行的。

所以,留给蛋卷的选择只有一个——直接生产测试,逐个功能完善;以用户为维度,逐个迁移,即:一个从1到N的逐步迁移的方案。

使用这个方案能保证几点:

  1. 问题范围可控。初期只有一个测试用户,即便数据有问题也容易处理。

  2. 测试用例可构造。使用生产环境,虽然测试时间会拉长,但实际效率会高很多。

要实现这个方案,意味为存在两个交易系统长期并行的情况,因此需要解决2个关键问题:

  1. 用户需要按照用户ID路由到不同系统。这个问题相对简单。

  2. 因为外部存在第三方系统,蛋卷内部虽然是2套系统,但是外部能看见的只能是一套。好在整个基金交易系统的外部依赖,大部分是基于文件交换,这个问题就容易处理很多了。

因此,蛋卷对交易系统,做了以下改造:

  1. 下图中①所示,增加了根据UID进行路由的处理,不同用户路由到不同交易系统

  2. 下图中②所示,外部系统交互,增加了一个处理文件的Proxy,负责外部文件的合并和拆分

  3. 下图中③所示,部分管理、配置数据仍留在原系统,通过数据库方式,直接进行信息同步

图片

基于以上架构,蛋卷历时10个月时间,从无到有搭建了自有交易系统,并顺利实现了用户无感知迁移:

  1. 项目初期实现路由、文件Proxy以及几个独立的功能场景,如申购、赎回场景。我们就直接上了生产环境,使用一个用户测试。后续功能边开发、边测试。极端情况这一个用户出现问题,采用手工修改文件的方式处理。

  2. 用户迁移需要谨慎。由于2个系统并行,从三方系统迁移到蛋卷后,如果用户做了交易,是无法再回退到三方系统的。特别需要注意,用户有在途交易或者未完全结束的交易时(如认购),迁移也是有风险的。因为有些数据存在中间状态,所以蛋卷对这类用户,则等到彻底无任何中间数据后再进行迁移。

  3. 用户迁移与新功能并行。用户迁移周期时间比较长的,大致持续了3~4个月,为了保证开发节奏,很多新功能我们直接在新系统上实现,但是这些功能对未迁移用户是无法使用的。针对这种情况,我们在App端做了功能配置开关,保证迁移、新功能开发能并行。

最终实现的基金核心交易模块(与交易相关模块)大致如下:

图片

相对以前第三方系统,使用自有系统带来了效率的巨大提升:

  1. 新功能随时发布、随时上线,不存在需要停机的问题

  2. 大量的自动化。比如:基金业务相关文件的导入、业务逻辑处理,无需人工介入

  3. 支付环节的动态路由

  4. 系统中大量对账的提取、抽象、模型化,简化了重复过程

| 支付环节的优化

在基金交易系统中,用户申购是很重要的环节,因此蛋卷对接了多家第三方支付。不同的第三方支付,能支持的银行不同、相同银行可能支持的支付额度不同、支付费率不同。在自有交易系统的基础上,我们可以结合不同银行的特点,实现支付渠道的动态配置。如下图。

图片

其中结合了手动配置与自动配置。手动配置用于推荐某些渠道、个别银行以及一些系统维护时处理。自动配置根据在出现支付渠道故障时可以自动切换或者服务降级,以及可以根据代码实现具体支付的路由规则(如:选择综合费率最便宜的渠道)。

| 总结

回顾整个自建交易系统的过程,尽早上线、逐个用户迁移是唯一可行的方案,也是最安全的方案。虽然看似在功能不全的情况下上线,但是只要问题是可控的、有限的、能预估的,那么就没有问题。这种方式同时还尽早暴露了上线风险,虽然早期问题会比较多,但是越往后会越舒服。

最后,对于自己不可控的第三方依赖,是非常痛苦的,在可能的情况下应该尽量去掉。长痛不如短痛,如果一个事情迟早要做,那么可以考虑下是否现在就开始动手。

| 还有一件事

雪球的工程师团队在招聘,Java 工程师,运维开发工程师,测试开发工程师,算法工程师,有意的同学可以查看原文看看具体的职位和要求,就等你了。