跳至正文
Starone

参考架构

示意

高性能交易平台

一个面向金融交易的微服务平台,基于 Java、Spring Boot、Kafka、Redis 和关系型账本构建,设计上正确性第一,吞吐量第二。

问题

设想一个平台,它从 Web、移动端和合作方渠道接收支付或转账指令,并且必须把每一笔恰好记录一次。业务量并不均匀,在发薪日、促销活动和结算截止时点前后会出现陡峭的峰值。下游网络和合作方系统比平台自身被期望达到的水平更慢,也更不可靠。

难点不在于纯粹的速度,而在于当客户端重试、消息重复到达、节点在交易中途故障、外部方超时却不说明自己是否已经执行时,仍然保持正确性。一个在压测中表现出色、却解释不了一分钱去向的设计,是不合格的。

设计必须满足的需求

  • 从客户的角度看,一笔交易必须恰好生效一次,即使客户端或内部组件发生了重试。
  • 账本必须始终保持平衡,每一笔资金变动都记录为不可变的复式分录。
  • 平台必须通过水平扩展吸收峰值负载,既不需要重新设计,也不降低余额的一致性。
  • 任何单个服务、节点或可用区的故障,都不得丢失一笔已受理的交易。
  • 每一次状态变更都必须可审计,内部记录必须与外部结算文件进行对账。
  • 运维人员必须能够近实时地看到延迟、错误率、队列深度和业务异常。

设计

组件

高性能交易平台
  1. 渠道

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

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

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

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

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

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

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

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

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

API 网关

网关负责终止 TLS、认证调用方、按客户端限流,并校验合作方流量的请求签名。它要求每一个会改变状态的请求都携带幂等键,并将其传递给下游。网关之后的任何组件都无法从公网直接访问。

02

交易服务

无状态的 Spring Boot 服务分别处理发起、授权、限额和记账,各自处在自己的限界上下文内。一笔交易沿着显式的状态机流转,因此它的状态始终是少数几个已知取值之一。这些服务在网关之后水平扩展,不持有任何会在重启时丢失的状态。

03

账本数据库

关系型数据库以只追加的分录形式保存复式账本,余额由分录推导得出。ACID 事务和约束在提交时强制保证借贷相等。只读副本承担对账单和报表查询,使分析类查询不与写入路径争抢资源。

04

Kafka 事件主干

每个服务在同一个数据库事务中写入状态变更和一条 Outbox 记录,再由中继程序把 Outbox 发布到 Kafka。主题按账户或交易键分区,在需要的地方保证顺序。消费者是幂等的,反复失败的事件会被路由到死信主题以供排查。

05

Redis 缓存与协调

Redis 保存幂等记录、限流计数器,以及限额和参考数据这类短时缓存的读取结果。它被当作加速器,而绝不是记录系统。如果 Redis 不可用,平台会变慢,但余额依然正确,因为余额是从账本读取的。

06

对账与审计

对账服务把内部分录与结算文件和合作方文件逐笔匹配,对任何未匹配或不一致的记录生成差异项。差异项通过运营队列处理,并保留完整的处理历史。不可变的审计日志记录了每笔交易由谁、由什么、在何时变更。

07

云基础设施

服务以容器形式运行在跨多个可用区的 Kubernetes 上,数据库采用主库加同步备库的部署方式。基础设施用 Terraform 定义,部署采用渐进式发布,有问题的版本只会先触达一小部分流量。备份会按计划执行恢复,以证明恢复确实可行。

08

监控与告警

指标、日志和分布式追踪通过交易标识从网关一路关联到账本。服务等级目标覆盖延迟和错误率,Kafka 消费者滞后则作为故障的早期信号受到关注。业务告警,例如异常的拒绝率或不断增长的对账积压,与技术告警并列呈现。

取舍

设计决策

决策理由
以关系型数据库作为权威账本在这里,强一致性和事务约束比最终一致性存储的写入扩展能力更有价值。代价是账本会成为扩展上的约束,应对方式是保持事务短小、必要时按账户区间分区,并把读取转移到副本。
用事务性 Outbox 取代双写分别写入数据库和 Kafka 会留下一个窗口:一方成功而另一方失败。Outbox 增加了一个中继组件和少量发布延迟,换来的保证是:每一个已提交的变更最终都会发布,未提交的变更永远不会发布。
在网关执行一次幂等校验,在账本再执行一次客户端和网络都会重试,至少一次的消息投递也会带来重复。在边缘检查幂等键可以低成本地处理常见情况,而账本中的唯一约束是最后一道防线,即使缓存丢失也依然有效。
授权同步,其余一律异步客户需要立即得到一个明确的答复:交易是否已被受理,因此这条路径是同步的,并保持简短。通知、报表、风险评分更新和结算由事件驱动,这使它们不占用延迟预算,并且可以各自独立地失败和恢复。
按业务能力而不是按技术分层拆分服务微服务会带来运维成本:更多的部署、更多的网络调用和更困难的调试。只有当各项能力的扩展节奏或变更节奏不同时,拆分才有道理,因此设计从少量服务起步,没有具体理由就不再继续拆分。

预期成效

  • 账本从构造上保持平衡,并能解释每一笔资金变动
  • 重试和重复消息不会产生重复交易
  • 容量通过增加实例和分区来增长,而不是靠重新设计
  • 与外部方的差异由对账发现,而不是由客户发现

该设计旨在达成的目标。仅为示意,并非客户项目的实测结果。

代表性技术

  • Java
  • Spring Boot
  • Kafka
  • Redis
  • PostgreSQL
  • Kubernetes
  • Docker
  • Terraform
  • AWS
  • OpenTelemetry
  • Prometheus
  • Grafana
全部参考架构

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

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