金融科技工程手册 – 构建金钱关键系统的完整指南
金融科技工程手册 – 构建金钱关键系统的完整指南
TL;DR
金融科技工程手册规范了构建以金钱为核心数据模型的软件所需的不可变、可审计、无信任的模式。 内容涵盖从金钱表示到账本设计、外部集成、访问控制以及测试,每一部分都围绕三大指导原则展开。
谁应该使用本手册?
- 新入职的金融科技员工 – 快速了解领域特定模式和术语的速成课程。
- 有经验的金融科技工程师 – 解决具体问题的参考手册,也是跨团队讨论的共享语言。
- 非金融科技领域的工程师 – 了解金钱系统为何不同于普通 Web 应用的入门指南。
鼓励大家贡献内容;本文档旨在持续演进。
核心原则
| 原则 | 强制实现的内容 | 常见机制 |
|---|---|---|
| 不产生虚构数据 | 金钱不能随意出现或消失。 | 幂等键、去重、复式记账、预留。 |
| 不丢失数据 | 每一次金钱事件必须被持久化并可追溯。 | 全精度类型、至少一次投递、事件溯源、不可变审计日志。 |
| 不信任 | 外部提供方和内部组件都不被默认可靠。 | Webhook 签名、模式校验、跨源对账、显式错误处理。 |
金钱的表示
精度处理
- 避免使用浮点数 – 它会导致非确定性的四舍五入。
- 使用整数的最小单位 表示法币(例如,将 €12.34 存为
1234)。加密货币通常需要任意宽度的整数,因为代币小数位数可达 18 位。 - 任意精度库(
BigDecimal等)非常适合用于外汇或定价等中间计算。 - 有理数 能保证零精度损失,但速度较慢且序列化更困难。
关键规则: 将金额以最小单位的整数存储,并使用高精度类型进行计算;序列化时使用字符串或整数,绝不要使用 JSON 数字。
四舍五入策略
- 显式四舍五入 – 每一次除法、转换、费用或精度变更都必须调用四舍五入步骤。
- 业务驱动的方向 – 为避免超支而向下取整,或为统计公平使用银行家舍入;选择会影响税务/法律结果。
- 尽可能晚地四舍五入 – 在持久化或展示给用户之前保持完整精度。
- 处理残余 – 在拆分金额时,跟踪四舍五入产生的剩余,以防止余额漂移。
关键规则: 四舍五入绝不能创造或销毁金钱;残余必须放入专用账户。
货币处理
- 将金额和货币一起封装在
Money类型中。 - 禁止跨不同货币进行算术运算;转换必须使用受控汇率并显式进行。
- 在系统边界处根据精心维护的列表校验货币代码。
- 对于加密货币,使用
(网络, 合约地址)而非 ISO 4217 代码来标识资产。
外汇汇率
- 汇率是 有方向性的 – EUR/USD ≠ USD/EUR;买卖价差意味着倒数并非简单的倒数。
- 时间戳很重要 – 实时估值使用当前汇率,税务或报表使用价值日汇率。
- 区分 交易汇率(实际转换时使用)和 参考汇率(用于估值的中间价或央行汇率)。
- 没有唯一的权威来源;始终保存来源标识以便审计。
记录金钱:账本
复式记账
- 每一笔分录都将相同金额从 贷方 账户转移到 借方 账户,确保账目始终平衡。
- 余额是派生的,从不直接存储。
- 账户类型(资产、负债、权益、收入、费用)强制会计等式
资产 = 负债 + 权益。 - 更正通过冲销分录实现;原始行保持不可变。
时间维度
- 价值时间 – 经济事件发生的时间。
- 记账时间 – 事件在系统中被记录的时间。
- 结算时间 – 实际资金转移的时间(通常表示为 T+X)。
- 必须记录全部三个时间戳,合并会丧失可重建性。
审计与审计日志
- 捕获每一次变更的 何事、何时、谁/何物、为何——不仅是余额更新,还包括配置变更、权限更新和规则评估。
- 事件溯源 将事件日志视为唯一真相,使审计日志成为核心。
- 不可变性 – 追加写存储、运行时检查和防篡改(哈希链)防止静默编辑。
- 冲销 vs. 更正 – 冲销抵消原始分录;更正则发布净差额,保留历史。
执行金钱流动
不变量
- 通过 构造时(类型安全构造函数、数据库约束)、运行时(断言、基于属性的测试)以及 事后(对账作业)来强制关键属性。
资金预留
- 在调用外部服务前预留资金;区分 总余额 与 可用余额(
available = total – reserved)。 - 预留必须 线性化,并且始终得到解决(释放或结算),以避免死锁资金。
透支处理
- 区分 有意的 透支(信用产品)和 无意的 透支(外部不匹配导致)。
- 不要把 “余额 ≥ 0” 作为硬类型约束;应作为不变量并显式处理违规情况。
幂等性
- 使用 显式幂等键,范围限定为操作和客户端。
- 将重复投递视为单一逻辑效果;重试必须折叠为一次结果。
- 幂等性应在系统的 入站 与 出站 两侧都实现。
完全可恢复性
- 将长时运行的流程建模为 持久化状态机;每一步后持久化进度。
- 外部驱动器必须检测不完整的流程并恢复它们。
- 每一步必须 幂等;外部副作用不可恢复,因此要么前向重试,要么发出补偿动作(Saga 模式)。
外部世界
调用 API
- 积极校验 响应;遇到意外的模式变化时要大声报错。
- 预期 所有调用都会失败 – 实现重试、超时和指数退避。
- 持久化每一次请求和响应 – 这构成审计日志的一部分,并支持重新处理。
- 对关键路径考虑 提供商冗余,但要注意随之而来的复杂性。
处理 Webhook
- 不要信任顺序、有效性或投递保证。
- 保存 原始负载 并验证签名(HMAC 或非对称)。
- 将 webhook 视为 触发器,随后通过提供商 API 拉取权威状态。
- 快速返回确认(2xx),异步处理;确保幂等处理。
可靠通知(Outbox / CDC)
- 与状态变更 事务性 地发布事件(outbox 表)或使用 变更数据捕获 流式传输已提交的行。
- 投递为 至少一次;消费者必须使用稳定的事件 ID 去重。
对账
- 定期(每小时、每日等)将内部记录与外部来源对比。
- 以提供商生成的 ID 为匹配依据;若不可用,使用启发式(金额 + 时间戳)。
- 通过 更正分录 或重新处理来解决不匹配,绝不能覆盖历史数据。
控制与访问
职责分离 & 四眼原则
- 对任何可能移动或误报资金的操作(大额提现、账本更正、费用表变更)要求第二位审批人。
- 记录 谁发起 与 谁批准;批准必须是不同的主体。
访问控制
- 通过基于角色的访问控制(RBAC)实现 最小特权。
- 使用与金钱事件相同的审计字段记录每一次授权/撤销。
- 定期进行 重新认证,以发现过期的权限。
变更轨迹(SDLC)
- 将 源码控制历史 视为代码变更的权威记录。
- 强制代码审查、受保护分支和签名提交。
- 部署必须可追溯(谁、何时、哪个版本),以便将事故关联到相应的变更。
金钱关键系统的测试
- 基于属性的测试 – 对任意输入断言不变量(例如,总借方 = 总贷方)。
- 每一步后的不变量检查 – 自动验证账务规则在生成的操作序列中的每一步都成立。
- 生成式幂等性测试 – 重复每个操作并确认没有双计。
- 崩溃与恢复注入 – 在步骤之间模拟故障,以验证可恢复性。
- 往返测试 – 序列化/反序列化金钱类型,确保无精度损失。
- 金色测试 – 固定复杂计算(费用、对账单),检测回归。
- 向后兼容性测试 – 验证当前代码能够读取历史事件格式。
- 生产环境测试 – 运行金丝雀或合成交易,使用真实金钱并打标签以便后续冲销;绝不绕过账本。
附录
附录 A – 领域词汇表
列出金融科技关键术语的简要清单(账本、IOU、最小单位、买卖价差、T+X 等),并提供指向手册相应章节的链接。
附录 B – 端到端流程示例
- 加密货币提现 – 演示幂等性、预留、合规检查、链上广播、最终性等待、账本记账和对账。
- 卡片存款 – 展示 webhook 处理、清算账户、结算延迟和冲销。
- 应用内兑换并返现 – 突出货币隔离、精度保持、边界四舍五入以及对价差收入和促销费用的复式记账。
结论
金融科技工程手册提供了一个 自包含、以原则为驱动的蓝图,用于构建金钱不可被虚构、不可被丢失、也不可被隐式信任的系统。遵循本文所述模式——精确的表示、不可变的复式账本、显式不变量、稳健的外部集成、严格的访问控制以及全面的测试——工程师们能够交付经得起审计、监管审查以及分布式系统必然故障的可信金融产品。