跳至正文
Starone

解决方案

每一笔资金流动都有账可查的金融系统

我们构建支付、账本、钱包和信贷平台,其首要要求是正确性:没有一笔交易丢失,没有一笔交易被重复执行,每一个余额都能由其背后的分录解释清楚。

问题域

金融软件有一个大多数软件不具备的特点:它的错误以金钱计量,并且会被客户、财务团队和监管机构注意到。一个超时后被重试的请求,可能变成一笔重复付款。以单个可变数值保存的余额,可能与本应解释它的交易逐渐偏离。服务商的结算文件与内部记录之间,可能存在一笔谁也追查不出来源的差额。这些都是工程层面的故障,都有成熟的解决办法,而这些办法必须打在地基里。

这个地基就是账本。复式记账账本把每一笔资金流动记录为跨账户、借贷平衡的分录,只追加不修改,余额由分录推导得出。支付、钱包、信贷和手续费,都是建立在账本之上的产品。围绕账本的,是让它在分布式系统中值得信赖的一系列机制:每一次写入的幂等、每笔支付的显式状态机、可靠的事件发布,以及与每一个外部参与方的对账。

Starone 提供的是工程服务。我们不持有金融牌照,也不声称获得任何监管批准。系统的设计用于支持运营该系统的持牌机构履行其义务,包括记录保存、审计、客户尽职调查和报告。哪些义务适用,由客户及其合规与法律顾问判定。

难在哪里

工程挑战

01

重复交易与丢失交易

网络可能在请求与响应之间发生故障,调用方因此无法知道付款是否已经发生。不加保护地重试会让客户被扣款两次;不重试则让付款悬而未决。每一个涉及资金划转的操作,都需要一个幂等键,使重复请求返回最初的结果。

02

无法解释的余额

直接更新余额字段会丢失历史,并且在两笔交易同时触及同一账户时引发竞态条件。数字出错时,没有任何东西可供审计。余额必须由不可变的账本分录推导得出,任何缓存的余额都应视为一个可验证的投影。

03

结果不确定的外部服务商

卡处理机构、银行和支付网络以异步方式响应,会超时,会乱序发送 webhook,偶尔还会在几天后冲正某个结果。把服务商调用简单地当作成功或失败,就会产生卡住的和对不上的付款。每笔支付都需要一个状态机,显式建模“处理中”“未知”和“已冲正”这些状态。

04

拖到月末才做的对账

内部记录、服务商报告和银行对账单,以不同的格式、在不同的时间描述同一笔钱。如果只是定期手工比对,差异就会不断累积,成因也无从追查。对账需要自动化并持续进行,每一个未匹配项都作为被跟踪的异常提出来。

05

热点账户上的并发

商户结算账户或手续费账户,可能被全部交易中的很大一部分触及。简单的行锁会让它成为瓶颈,不够谨慎的乐观并发方案又会允许透支。账本设计必须有意识地处理争用,同时仍然防止余额跌破其限额。

06

关键路径上的合规检查

名单筛查、身份验证和交易监控依赖第三方服务,而这些服务有各自的延迟和故障模式。如果它们是事后拼接上去的,一次服务中断要么阻塞所有客户,要么让交易在未经检查的情况下悄悄放行。流程必须定义当某项检查缓慢、不可用或返回疑似命中时该怎么办。

我们如何构建

架构

平台以只追加的复式记账账本为核心,支付编排、服务商集成和合规服务围绕它构建,并通过可靠发布的事件相互连接。

  1. 01

    复式记账账本服务

    每一个财务事件都记录为一笔交易,其借方与贷方分录合计为零,在 PostgreSQL 这类关系型数据库中,以可串行化隔离级别或经过审慎设计的加锁事务原子写入。分录从不更新或删除;更正通过新增冲销分录完成。金额以最小货币单位的整数存储,并显式标明币种,绝不使用浮点数。

  2. 02

    幂等 API 层

    所有变更类接口都要求调用方提供幂等键。幂等键、请求指纹和最终响应,与业务效果在同一个事务中存储,因此重试会返回已保存的结果,而用同一个键提交不同的请求内容则会被拒绝。同样的原则也适用于入站 webhook 和消息消费者。

  3. 03

    支付编排

    每笔支付都是一个持久化的状态机,具有已创建、已授权、已请款、已结算、已失败和已冲正等明确定义的状态转换。编排器驱动状态转换,通过适配器调用服务商,并在未收到响应时安排状态查询。在发起外部调用之前,先在账本中冻结资金,再依据结果释放或确认。

  4. 04

    服务商与支付通道适配器

    银行、卡处理机构、支付网络和钱包体系各自由一个适配器包裹,对它们的 API、错误码和 webhook 格式做归一化处理。适配器负责超时、带退避的有限次重试和熔断。在商务安排允许的前提下,路由规则可以在某个服务商劣化时把流量导向备选服务商。

  5. 05

    客户准入与合规集成

    客户准入是一个工作流:收集数据,调用身份验证和制裁名单筛查服务商,并把不确定的结果转入案件队列交由人工审核。交易监控消费事件流,依据可配置的规则发出告警。工作流为服务商超时定义了明确的行为,因此“暂挂还是继续”是一项有记录的策略。

  6. 06

    对账引擎

    服务商结算文件、银行对账单和内部账本分录被摄取、归一化,再依据可配置的规则按参考号、金额和日期进行匹配。匹配成功的条目自动关闭。未匹配和部分匹配的条目成为异常,各有负责人和账龄计时;数据源能支持多高的频率,引擎就以多高的频率运行。

  7. 07

    审计、报表与事件流

    状态变更通过事务性发件箱发布到 Kafka 这类持久化日志,由它向报表存储、监控和下游系统供数,而不给账本数据库增加负载。不可变的审计记录保存了谁在何时做了什么,包括运营人员的操作。监管报表和管理报表由这些存储生成,并可追溯到源分录。

高性能交易平台
  1. 渠道

    • Web
    • 移动端
    • 合作方 API
    • 批量文件
  2. API 网关

    • 身份认证
    • 限流
    • 幂等键
    • 请求签名
  3. 交易服务

    Java 与 Spring Boot,无状态,水平扩展

    • 支付发起
    • 授权
    • 账本记账
    • 限额与风控
  4. Kafka 事件主干

    • 交易事件
    • Outbox 中继
    • 分区主题
    • 死信主题
  5. 账本数据库与 Redis

    账本是权威数据,缓存不是

    • 复式记账账本
    • 只读副本
    • 余额缓存
    • 分布式锁
  6. 对账与审计

    • 结算匹配
    • 差异检测
    • 不可变审计日志
    • 报表导出
  7. 监控

    • 延迟与错误率 SLO
    • 消费者滞后
    • 链路追踪
    • 业务告警
这条交易路径的设计原则是:账本是唯一的事实来源,事件记录每一次状态变更,对账则独立确认两者一致。

一次合作交付什么

  • 账本设计,含会计科目表与过账规则
  • 带公开契约的幂等支付与钱包 API
  • 支付状态机与服务商适配器
  • 与 KYC 及筛查服务商集成的客户准入工作流
  • 带异常管理的自动化对账
  • 审计轨迹与报表数据存储
  • 覆盖超时、重复与冲正的故障模式测试套件

开始之前

需要尽早做出的决策

自建账本,还是使用现有账本
账本在概念上很小,在细节上却不容出错。当成熟的开源或商用账本的账户模型契合您的产品时,采用它可以节省时间。当您需要现有方案无法提供的过账规则、多币种行为或性能特征时,再自建,并为正确性所要求的测试留出预算。
强一致性,还是最终一致性
账本写入以及为其把关的余额检查必须是强一致的;这里没有最终一致性的位置。由账本派生的一切,例如对账单、通知、分析和搜索,可以是最终一致的,并由事件驱动。把这条界线划清楚,关键路径才能保持短小而快速。
一家支付服务商,还是多家
单一服务商更容易集成、对账和推理,是合理的起点。当可用性目标、地域覆盖或成本有需要时,再增加第二家。多家服务商意味着多份对账数据源、各不相同的争议处理流程,以及本身也需要测试的路由逻辑。
如何扩展交易吞吐量
首先消除争用:对热点账户批量过账,使用子账户,并保持事务简短。然后通过只读副本和投影扩展读取能力。只有当一个经过充分调优的单库被证明确实是瓶颈时,才按账户或租户对账本分区,因为跨分区转账会带来实实在在的复杂度。

常见问题

常见问题

Starone 是持牌金融机构吗?

不是。Starone 是一家工程公司。我们为已持有或正在申请相关牌照的机构设计并构建技术系统。我们不声称获得任何监管批准,牌照事宜和对监管规定的解读由客户及其顾问负责。

如何防止重复扣款?

在每一层都做到幂等。客户端请求携带幂等键,并与账本过账原子地记录在一起;调用服务商时,凡服务商自身提供幂等机制的都加以使用;消息消费者记录已处理的消息标识。重复的请求会返回最初的结果,而不是产生一笔新的资金流动。

平台能否支持银行卡数据与相关安全标准?

架构的设计目标是把暴露面降到最低,通常做法是使用服务商的托管字段和令牌化,使原始卡数据不进入您的系统。网络分段、加密、密钥管理和访问日志在设计上与 PCI DSS 等框架对齐。正式的评估与认证由运营主体会同具备资质的评估机构完成。

上线前如何测试故障场景?

通过注入故障。测试套件模拟服务商超时、重复和乱序的 webhook、过账过程中的部分失败,以及事务中途的进程崩溃,然后断言账本依然平衡,没有支付丢失或重复。对账则用故意制造差异的文件来演练。

有一套必须在生产环境中正常运行的系统?

告诉我们您正在构建什么。工程师会阅读您的留言,并在两个工作日内回复。