对金融行业而言,核心系统的稳定与高效运作至关重要。尤其在基金公司,账务类核心系统承载着大量复杂的业务逻辑与数据处理,这不仅是企业运营的基础,更是应对市场变化的关键。
在 2024 FCon 全球金融科技大会 上,天弘基金技术研发部高级架构师刘晓斐带来了题为《天弘基金账务类核心系统的挑战和实践》的专题演讲,其演讲聚焦于金融核心系统,特别是基金行业的账务系统所面临的两大挑战:复杂性和不确定性。系统复杂性源于业务的复杂度和系统熵增,而不确定性则体现在风险管理上,没有任何系统能够完全避免风险事件。
以下为演讲实录(经 InfoQ 进行不改变原意的编辑整理):
在当前数字化浪潮中,我们经常听到业务与技术的融合,这种融合被形象地称为“双向奔赴”。在这样的背景下,我们的讨论往往围绕着业务与技术的结合展开。今天,我将分享的主题聚焦于一个更为细分的领域——账务类核心系统。
我们可以借用类比。假设我们都是技术专家,在设计任何应用系统时,我们的初衷可能是为了进攻或防守,这与战争策略颇为相似。在战争中,有前线和后方腹地之分。以当前的俄乌冲突为例,前线战场主要在乌克兰境内,但最近乌克兰军队深入俄罗斯腹地的库尔斯克地区,给俄罗斯带来了不小的压力。将这个类比应用到金融系统中,我认为账务系统就像是整个金融排兵布阵中的腹地。虽然它可能不会直接参与前线的业务,如销售或投资,但它为整个系统提供了坚实的基础和支撑。
我们先了解一下账务系统的业务类型。在进行业务类型划分时,通常有几种不同的方法。一种是基于数据模型的划分,这包括余额模型和单据模型等。另一种是根据记账方式,比如单边账和双边账。我更倾向于从业务角度出发,按照记账对象来进行划分。
围绕天弘基金会计主体的账目,我们分为“三本账”。我们有销售侧的客户账。这部分的目的是募集客户的资金,并将这些资金引入基金产品中。我们需要精确记录客户的每笔资金,清晰地描述客户的资产状况。当资金募集完成后,它们会流转到产品的投资端。在投资端,资金会进入金融市场,用于购买股票、债券等各种金融资产。这些金融资产同样需要一个账来记录,我们称之为产品账。最后,随着资金的进一步流转,会涉及公司的会计主体。在整个运作过程中,公司会收取一些费用作为收入,同时在销售侧也会发生一些营销费用的支出,这些则称之为财务账。
在探讨基金行业账务系统的技术形态时,我认为核心任务可以概括为“记清账、算清账和结清账”的过程。在这个过程中,我想强调基金行业账务系统的一些技术特征。
首先,基金行业账务系统的输入输出主要依赖于文件。与外部机构,无论是销售机构还是托管行的交互,基本上都是通过文件进行的。实时接口相对较少,系统之间的通信和数据交换大多采用文件传输的方式。
其次,账务系统的计算形式主要是批处理。在日常操作中,系统很少实时处理数据,而是通过批量处理的方式来执行计算任务。这种计算模式有助于处理大量数据,但可能在实时性方面存在一定的局限性。
最后,账务系统数据规模。我们的记账系统需要处理的数据量达到了亿级,甚至是十亿级。这样的数据量对系统的处理能力和存储能力提出了很高的要求。
基于业务和技术的输入,我们识别出了基金信息系统作为整个金融系统后方腹地所面临的主要威胁。以下是我们识别的一些头部问题。
首先,我们面临的问题之一是复杂性。以我们团队的一个小样本为例,新员工成功越过学习门槛的比例大约是 50%。这意味着每两个新员工中便有一个人就很难适应这种高难度的学习要求,需要极长的时间去调整。
其次,风险不确定性问题。我相信在座的各位技术同行都曾遇到过各种风险问题。在我们的账务系统中,这一点尤为明显。以月均交收为例,我们的资金规模达到了千亿级。在这样的规模下,即使是极小的损失,比如千分之一或万分之一,都是我们无法承受的后果。
第三,业务不确定性问题。所有技术同行可能都遇到过这样的情况:一个业务需求来了,但在实施过程中发现难度非常大。我们将这种情况归类为业务不确定性问题,并将其分为两个截然不同的方向。一方面是市场不确定性,业务部门需要进行各种创新以应对市场的发展。在这种情况下,我们需要尽可能地支持业务拓展和创新,这是一种挑战。另一方面是监管不确定性,监管机构需要控制市场波动,保护投资者利益,这可能会实施相关约束,要求我们在各类安全的范围内实施创新。
在面对基金账务核心系统的复杂度挑战时,我们可以通过一些具体的例子来理解这一问题。例如,参数复杂度,在一个基础的系统中,我们可能需要处理多达 3000 个参数,这还不包括字典。如果考虑到测试,这些参数会形成一个树形分支结构,其复杂度呈指数级增长,即 n 的 m 次方,这使得保证测试覆盖度变得非常困难。
文件复杂度也是一个问题,尤其是在我们有余额宝等业务场景的情况下。我们每天需要处理的文件数量超过 200 万个,数据量达到 1.5TB 左右。这样的文件处理量对系统的性能和稳定性提出了极高的要求。
逻辑复杂度同样不容忽视。例如,我们在 2022 年采购的某系统中,某单个类的源代码行数超过 1 万行,这种复杂度使得维护和理解代码变得极其困难,甚至可以说是“反人类”的。
数据复杂度也是一个挑战。当我们拥有超过 10 亿的账户数据时,即使是极小概率的事件,如 1/10,000 的概率,在这样庞大的数据基数下也会变成一种必然事件。
为了应对这些复杂度挑战,我们采取了一系列治理措施。治理的第一步是进行分类。我们认为复杂度的来源可以分为三类:第一类是由系统熵增导致的,这是一个物理概念,指的是在一个封闭系统中,如果没有外力作用,系统会从有序向无序转变。第二类是由业务本身的复杂度导致的,我们认为系统是业务的数字孪生,因此会自然继承业务的复杂度。第三类是多系统之间的非线性依赖性和组合,这可以用三体问题来形象说明,即三个太阳组成的一个系统,使得地球科学家无法精确计算出适合人类生存的时间段。通过这样的分类,我们可以更有针对性地对基金账务核心系统的复杂度进行治理,以提高系统的稳定性和效率。
我们首先关注熵增问题,即系统从有序状态向无序状态的自然演变。要逆转这一过程,需要外部力量的介入。在封闭系统中,这种逆转是无法自发发生的,但通过外部努力,我们可以将系统重新变得有序。我们具体采取了以下几个步骤来实现这一目标。
信息剪枝:我们采用了计算机科学中的经典算法,如深度优先搜索和广度优先搜索,来剪除不必要的参数分支。在处理 3,000 多个参数时,我们发现许多参数在实际业务场景中是不变的,或者存在重复。我们的目标是消除这些不必要的变化和重复,从而简化系统。例如,我们识别出在产品域、销售商域和产品销售商域中重复的参数,并将它们统一到一个逻辑域中,这样就完成了信息剪枝的过程。
信息压缩:我们对参数进行了压缩,将表达多个变化方向的复合性参数简化。以净值披露频率为例,我们发现参数主要围绕三个方向变化:年月日、净值预设和信息披露环节。通过这种方式,我们将 3,000 多个参数压缩到了 500 多个,显著减少了参数数量。
结构化管理:为了从无序到有序,我们对大量看似无关的参数进行了结构化管理。我们重新组织出了一批参数组合方案,每个方案都包含了相关性较强的参数。这样,无论后续是增加、修改还是删除参数,我们都能迅速找到它们所在的方案进行调整,确保系统的长期稳定运行,并避免参数数量的过快无序增长。
在处理由业务复杂度引发的系统复杂度问题时,我们认为这种复杂度是难以消除的,因为业务逻辑本身是固定的,除非它不合理,那将属于熵增的复杂度范畴。面对这种复杂度,我们采取了分而治之的策略,这是计算机科学中的经典算法。我们的具体工作包括以下几个方面。
1. 业务与技术的分离:我们首先要区分哪些复杂度是由技术引入的,哪些是由业务引入的。我们对模型进行了调整,将输入输出与核心账务模型分开,并将输入输出部分独立出来,创建了一个文件工厂。
2. 调度与批处理的分离:我们进一步将调度和批处理分开。调度负责解决所有任务的依赖关系,可以是顺序、分支或循环关系,我们将其实现为一个可编程的有向无环图(DAG)。批处理则负责处理数据片段的计算逻辑,我们调研了市场上的开源产品,实现了包括单机模式、广播模式和分片模式在内的多种处理模式。
3. 领域能力的拆分:在业务侧,我们没有拆分太多的微服务,因为我们的团队规模有限,只有 100 多人。我们认为,拆分过多的微服务会增加后期的维护成本。但我们仍然可以拆分领域能力,我们从底层向上拆分了几十到 100 个领域能力,这些领域能力是我们认为的最小复用单元和最小开放单元。这意味着它们可以被上层应用所组装,也可以被替换,以应对变化。
4. 原子层服务与业务场景的构建:在领域能力的基础上,我们构建了原子层服务,它们是对领域能力的进一步组装。然后,所有的业务场景都基于这些原子服务进行调用。从底层到上层,我们实现了从稳态到敏态的转变,尽量将不变的部分留在底层,而将变化的部分放在上层。
第三类复杂度是非线性依赖关系。我们面临的主要问题是循环依赖。为了解决这个问题,我们的目标是将复杂的网络依赖关系转变为更清晰的线性依赖关系。在这个过程中,文件管理是我们的核心。
我们对文件的理解是多层次的。文件不仅仅是数据的载体,它也是一种网络协议,包含了语法、语义和时序这三个网络通信的基本要素。在我们的文件工厂中,我们针对不同类型的文件定义了不同的处理方式,每一套文件处理流程都被视为一种网络协议。
基于这种理解,我们将文件视为一种服务,与 HTTP 和 RPC 接口类似。我们参考了服务治理的逻辑,进一步发展了文件治理的概念。文件治理涵盖了文件的传输、加工、拆分和合并等所有操作,其核心是对文件进行全生命周期的管理。
在文件治理的帮助下,我们可以记录所有文件的出入、拆分和合并活动。这样的记录使得我们能够清晰地知道每个文件的生产者和消费者是谁,从而进行有效的管理和控制。例如,在处理每天 200 万个文件的情况下,我们可以避免因一台机器的变动而影响到整个系统的稳定性,因为我们能够清楚地知道那些接口文件是由谁生产、谁消费的。
在讨论账务系统的复杂度时,我们提到的策略和方法并不是全部。例如,蒙特卡罗算法,这是一种通过简单模型模拟复杂现象的方法。以计算圆周率为例,通过在正方形内随机分布点,计算点落在圆内外的概率,可以模拟出π的值。虽然这种方法在我们的账务系统中难以直接应用,但它启发我们在其他场景中寻找解决方案。
复杂度之所以被放在风险不确定之前讨论,是因为我认为复杂度是风险产生的一个重要原因。风险往往难以预测,就像蝴蝶效应一样,一个小小的变化可能引起巨大的影响。因此,虽然风险管理非常重要,但我认为复杂度管理是风险管理的前提。
在具体的风险管理方面,我们面临几种类型的风险:
数据不平衡:证账实不一致;系统传输丢失、重复。
数据错误:逻辑错误;系统计算错误,以及重要配置错误等。
服务中断,这是所有系统都可能遇到的问题,需要通过技术手段来预防和解决
合规要求:在当前监管日益严格的形势下,合规性变得尤为重要。任何对客户利益产生不公平影响的行为都是不可接受的,尤其是在监管部门的审查下,可能会导致严重的后果。
因此,我们将风险分为三类:
服务不可用:所有的软硬件都会经历生命周期的自然过程,这是不可避免的问题,我们的目标是找到有效的方法来应对和解决这些问题。
资金损失:对于我们这样规模达到千亿级的系统,即使是极小比例的损失也是难以承受的。这类风险是我们必须坚决避免的。
科技合规:随着监管机构不断推出新的标准和要求,我们必须找到应对策略,确保系统的合规性。
可用性分析的一个关键特征是它涉及不同级别的故障,比如单机故障、共享设备故障,以及机房级的故障。这些故障的完全修复时间可能从小时到月不等。例如,去年北京遭遇了 140 年一遇的大雨,其中一个机房被洪水包围,我们搬迁设备就花了将近一个月的时间。这种情形下,等待可用性的完全恢复是不可控的,但不修复并不意味着业务会受到影响。核心逻辑在于我们必须要有一个 Plan B,即切换能力,以确保业务的连续性。
我们的应急框架包括故障发现、故障转移和故障恢复,这是一个标准的应急流程。但我们更想强调的是,我们的基础架构正在进行单元化改造,这在许多互联网企业中已经实施多年,我们也是近两年开始进行。所谓的单元,是指最小的容灾单元,同时也是最小的容量单元。如果一个单元,比如一个机房出现故障,我们可以从流量层或调度层将所有任务切换到另一个单元。单元化的核心逻辑是自洽,即当我们将流量切换走时,另一个单元必须有一个完备的生态系统,这个生态系统由一系列相互依赖的应用系统组成,确保在单元内能够独立运行。
在进行分片操作时,我们要考虑如何保证分片的逻辑。例如,我们可能会根据客户 ID 进行分片,但这并不是唯一的解决方案。我们可以参考外卖服务的分片逻辑,它们通常按区域 ID 进行分片,因为外卖服务往往涉及跨区域的交易。或者参考即时通讯服务,它涉及两个客户之间的通信,因此它的分片是按会话来进行的。这些例子表明,分片逻辑应该根据业务的具体需求来确定。我们的目标是从无序到有序,确保所有的调用链路在一个单元内自洽。在早期实施单元化时,我们还有一个约束条件,即不同单元之间的网络是不通的,这迫使各个应用系统在单元内解决问题,从而实现自洽。最终,机房被洪水包围下我们账务系统在分钟级就完成了切换,未产生任何业务风险。
在讨论资金安全风险时,我们认为大多数问题与变更有关,变更因素可能占到 80% 甚至 90%。因此,我们构建了一个事前、事中和事后的分析框架,专注于变更管理。在事前阶段,我们关注需求、研发和测试;在事中阶段,重点是发布;而在事后阶段,则关注上线后的交付和使用。我们发现,风险事件,尤其是资金安全风险事件,发现得越早,成本越低。在需求研发和测试阶段,发现问题的成本主要是二次代码变更的费用,对业务影响较小。而在发布过程中,如果出现问题,可能会导致发布延迟,影响业务进展;而在交付后,如果问题未能及时解决,可能直接导致资金损失。
在这个分析框架中,资金安全的分析通常涉及信息流和资金流的对齐。基于账务系统,我们识别出三类核心问题。第一类是业务逻辑的正确性,这是最难解决的问题之一。我们需要确认账户系统的计算是否正确。与业务伙伴合作时,他们建议我们在旁路再计算一次,但在基金行业,资源有限,通常很难保证同一岗位有两个人同时进行相同的操作。
为了解决这个问题,我们将计算拆分为两种情况。对于简单的计算,例如几个因子的乘积,我们可以在旁路再计算一次,因为公式相对稳定。而对于复杂的公式,旁路再计算的成本难以控制,因此我们将公式拆解为多个因子,逐一核对。例如,在计费用时,我们会检查每个因子的正确性,而不是直接核对最终费用。我们还采用阈值型核对,设定最小和最大费率,确保计算结果在合理范围内,从而避免出现极端错误。
第二类问题是跨系统的一致性。我们需要确保从文件到账务系统的导入和导出过程中没有数据丢失,最终的账务记录与最初的账务记录一致。这包括明细与汇总、出账和入账的核对等。
第三类问题涉及人工操作,包括运营类操作和运维类操作。根据我们的经验,这两类角色的权责必须清晰划分,以便长期推动工作。我们还要标准化每个角色的操作,尽量实现双人录入等复核机制。
在这个分析框架的基础上,我们构建了一个资金安全框架,分为事前、事中和事后三大类平台。事前,我们建立了全面的测试平台,以确保在早期阶段识别并解决所有潜在问题。在事中,我们关注预发策略和灰度发布,确保能够模拟和应对风险。在事后,我们建立了稽核平台,以便及时阻断风险。通过在这三个平台中沉淀经验,我们能够更有效地应对风险事件。我们希望在出现风险时,能够迅速响应,降低解决问题的成本,从而确保资金的安全。
合规是一条红线,我们必须达到及格线的基本要求,这是绝对不能妥协的。如果我们希望做得更好,得到监管机构的认可,就需要在设计和思考上投入更多的心思。
我们面临的一个具体挑战是国产化,也就是信创工作。我们首先需要明确,信创是目的还是结果。经过内部深入讨论,我们认为信创为我们提供了一个时间窗口,一个进行重要架构升级的机会。通常,这样的升级需要大量资源和管理层的批准,这是非常困难的。如果通过架构升级来实现信创,仅将信创视为架构升级的衍生结果,这将是一个非常好的时间窗口。
在实施信创时,我们还需要决定的是从一般系统还是核心系统开始?从风险和安全的角度来看,先从一般系统开始似乎更合理。但我们经过深思熟虑后,决定从核心系统开始。这是因为即使一般系统成功升级,也不能保证核心系统的升级不会遇到问题。一般系统无法完全模拟核心系统的复杂性、风险和场景。因此优先从核心系统启动相关工作,我们在去年年底完成了余额宝的信创工作,这为我们推动其他系统的信创工作提供了信心。
信创软硬件的兼容性是我们的另一个关注点。市场上有多家厂商提供信创软硬件,但我们无法预测哪家厂商能在市场竞争中存活下来。因此,我们必须为未来做好准备,确保即使我们选择的厂商未能存活,我们也能应对。同时,我们对市场上的信创软硬件的安全性和稳定性也持谨慎态度,因为它们还需要经过大规模市场的验证。此外,信创硬件的采购存在生产周期的问题,我们可能无法立即获得所需的硬件。因此,我们需要考虑多品牌的兼容性,确保底层品牌的变化不会对上层应用产生影响。基于这些考虑,我们制定了一个兼容性方案,通过兼容层来屏蔽不同品牌之间的变化,将对应用层的影响降到最低。
在进行风险管理时,我认为角色之间的平衡和制衡至关重要。例如,在产品、研发、测试和 SRE 这四个角色共同参与的过程中,如果我们假设每个角色都有 25% 的盲区,那么四个角色的盲区叠加起来将形成一个非常可观的风险区域。因此,我们需要通过有效的沟通和协作来减少这些盲区。
为了提高风险管理的有效性,我们实施了常态化的攻防演练。这不仅仅是一句空话,因为监管机构每年都会到现场进行演练检查,他们会提供一些预案,让我们进行推演。我们认为这是第一阶段的逻辑,即假设出现了某种情况,我们应该如何应对紧急情况。但这种演练的有效性很难判断,所以我们进入了第二阶段,即有准备的生产演练。所谓有准备的演练,是指我们会提前告知团队将在某一天进行演练,但具体的演练内容和时间不会提前透露。
在这种情况下,我们的 GOC 和 SRE 团队会直接进行故障注入,例如突然断电或拔掉网线,而不通知其他团队成员。这要求团队成员能够通过监控系统发现问题,并迅速做出应急响应和切换。这种演练对团队的监控发现率提出了很高的要求,如果监控发现率有问题,那么相关团队将面临巨大的挑战。从管理的角度来看,这种演练给团队带来了很大的压力,迫使他们必须做好风险管理。
未来,我们希望进行无准备的演练,即连演练的时间都不提前告知,突然有一天系统就可能出现故障,团队成员也无法判断这究竟是演练还是真正的生产事故。这样的演练将更加接近真实情况,有助于提高团队的风险应对能力。
最后我想提出一个开放性的问题供大家思考。在内部分享时,我曾提出不确定性是否只有负面影响,而没有正面影响。今天,我想将这个问题扩展到复杂度上,复杂度真的只有坏处吗?没有好处吗?
我个人的看法是,如果复杂度是不可避免的,并且能够被有效管理,那么它实际上可以成为一种竞争优势。简单的东西很容易被模仿、学习和传播,这样的特性并不能为企业提供一个有效的保护屏障。我们认为,有一句口号叫“做难而正确的事儿”,意味着如果某件事很难做,但它是正确的,那一旦我们做好了,这样的事就能为企业带来重要的护城河。即使这个方法被传播出去,其他企业想要追赶也需要时间和大量资源。
刘晓斐,天弘基金技术研发部高级架构师。先后就职于京东、搜狐、天弘基金三家公司,经历了互联网技术的快速发展时期,也经历了企业型架构在数字化背景下面临的挑战和破局。目前着力于将两种思路融合发展,探索一种适合企业型架构健康演进的长期方向。