完整的 App 钱包 + 第三方支付系统架构方案

一、整体系统架构

At the heart of every serious fintech product lies one foundational component: a robust, real-time ledger. Whether you’re building a digital wallet, launching a neobank, handling FX and cross-border settlements, or processing card transactions, you’re effectively operating a financial institution – and that means your ledger architecture needs to be bulletproof.

完整的支付系统通常分为以下几个核心子系统:

┌─────────────────────────────────────────────────────────────────────────────┐
│                              业务应用层                                       │
│   ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│   │  电商APP  │  │  会员系统 │  │  游戏充值 │  │  订阅服务 │  │  其他业务 │      │
│   └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘      │
└────────┴─────────────┴─────────────┴─────────────┴─────────────┴────────────┘
                                     │
                                     ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              交易编排层                                       │
│   ┌────────────────────────────────────────────────────────────────────┐    │
│   │                         Payment Service                             │    │
│   │  • 订单创建与管理  • 支付流程编排  • 状态机管理  • 幂等性控制           │    │
│   └────────────────────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘
                                     │
        ┌────────────────────────────┼────────────────────────────┐
        ▼                            ▼                            ▼
┌───────────────┐          ┌───────────────┐          ┌───────────────┐
│  Wallet       │          │  Payment      │          │  Ledger       │
│  Service      │          │  Gateway      │          │  Service      │
│               │          │               │          │               │
│ • 余额管理    │          │ • 渠道路由    │          │ • 复式记账    │
│ • 冻结/解冻   │          │ • 第三方对接  │          │ • 交易流水    │
│ • 充值/提现   │          │ • 回调处理    │          │ • 余额计算    │
└───────────────┘          └───────────────┘          └───────────────┘
                                     │
                                     ▼
┌─────────────────────────────────────────────────────────────────────────────┐
│                              清结算层                                         │
│   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐    │
│   │ Reconciliation│  │  Settlement  │  │   Clearing   │  │   Reporting  │    │
│   │   对账服务    │  │   结算服务   │  │   清算服务   │  │   报表服务   │    │
│   └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘    │
└─────────────────────────────────────────────────────────────────────────────┘

二、核心服务详解

1. Ledger Service(账本服务)- 最核心

Double-entry system is fundamental to any payment system and is key to accurate bookkeeping. It records every payment transaction into two separate ledger accounts with the same amount. One account is debited and the other is credited with the same amount. The double-entry system states that the sum of all the transaction entries must be 0. One cent lost means someone else gains a cent. It provides end-to-end traceability and ensures consistency throughout the payment cycle.

复式记账是支付系统的基石。这是区别于”简单余额字段”最关键的设计。

数据模型

-- 账户表 (Chart of Accounts)
CREATE TABLE ledger_accounts (
    id UUID PRIMARY KEY,
    account_type VARCHAR(20),      -- ASSET, LIABILITY, EQUITY, REVENUE, EXPENSE
    normal_balance VARCHAR(10),    -- DEBIT or CREDIT
    currency VARCHAR(10),
    name VARCHAR(100),
    parent_account_id UUID,        -- 支持账户层级
    metadata JSONB,
    created_at TIMESTAMP
);

-- 交易表(每笔交易)
CREATE TABLE ledger_transactions (
    id UUID PRIMARY KEY,
    external_id VARCHAR(100),      -- 幂等键
    description TEXT,
    status VARCHAR(20),            -- PENDING, POSTED, ARCHIVED
    effective_at TIMESTAMP,        -- 生效时间
    posted_at TIMESTAMP,           -- 记账时间
    metadata JSONB,
    created_at TIMESTAMP
);

-- 分录表(每笔交易的借贷记录)
CREATE TABLE ledger_entries (
    id UUID PRIMARY KEY,
    transaction_id UUID REFERENCES ledger_transactions(id),
    account_id UUID REFERENCES ledger_accounts(id),
    amount BIGINT,                 -- 整数存储,避免精度问题
    direction VARCHAR(10),         -- DEBIT or CREDIT
    currency VARCHAR(10),
    created_at TIMESTAMP
);

-- 约束:每笔交易的借方总额 = 贷方总额

账户类型设计

In this model, three accounts are involved: Art’s Wallet, Cash, and Card Processing Expenses. Art deposits $300 in his wallet balance using a credit card. To counterbalance the $300 credit (increase) on Art’s Wallet, we need two debit entries: One on the card processing fees account (increases by $6, or 2% of the transaction) One on the cash account.

典型的账户体系(Chart of Accounts):

资产类 (Assets) - 借方正常
├── cash:bank_account          # 公司银行账户
├── cash:payment_gateway       # 第三方支付待清算
└── receivables:pending        # 应收款

负债类 (Liabilities) - 贷方正常
├── user_wallets:{user_id}     # 用户钱包(欠用户的钱)
├── merchant_payables          # 应付商户款
└── pending_settlements        # 待结算

权益类 (Equity) - 贷方正常
└── retained_earnings          # 留存收益

收入类 (Revenue) - 贷方正常
├── transaction_fees           # 交易手续费收入
└── withdrawal_fees            # 提现手续费

费用类 (Expenses) - 借方正常
├── payment_gateway_fees       # 支付渠道成本
└── bank_transfer_fees         # 银行转账成本

关键交易示例

1. 用户充值 $100(通过信用卡,手续费 2%)

借 (Debit):  cash:payment_gateway     $98    (资产增加)
借 (Debit):  payment_gateway_fees      $2    (费用增加)
贷 (Credit): user_wallets:user_123   $100    (负债增加,欠用户)

2. 用户A转账 $50 给用户B

借 (Debit):  user_wallets:user_A      $50    (负债减少)
贷 (Credit): user_wallets:user_B      $50    (负债增加)

3. 用户提现 $80(手续费 $1)

借 (Debit):  user_wallets:user_123    $81    (负债减少)
贷 (Credit): cash:bank_account        $80    (资产减少)
贷 (Credit): withdrawal_fees           $1    (收入增加)

2. Wallet Service(钱包服务)

A double-entry ledger: Every wallet account must be backed by a ledger that logs debits, credits, and balance updates immutably. Balance calculation logic: Real-time account balances must reflect pending and posted transactions.

钱包服务是面向用户的抽象层,底层依赖 Ledger Service。

核心功能

  • 余额查询:从 Ledger 计算实时余额
  • 余额类型
  • posted_balance:已确认余额
  • pending_balance:待处理余额(如充值中)
  • available_balance:可用余额(posted – 冻结)
  • 冻结/解冻:支持订单锁定资金
  • 多币种:每个用户可持有多种货币

数据模型

-- 钱包主表
CREATE TABLE wallets (
    id UUID PRIMARY KEY,
    user_id VARCHAR(50),
    wallet_type VARCHAR(20),       -- PERSONAL, MERCHANT, SYSTEM
    status VARCHAR(20),
    created_at TIMESTAMP
);

-- 钱包币种余额(缓存,定期与 Ledger 对账)
CREATE TABLE wallet_balances (
    id UUID PRIMARY KEY,
    wallet_id UUID,
    currency VARCHAR(10),
    posted_balance BIGINT,
    pending_balance BIGINT,
    frozen_balance BIGINT,
    ledger_account_id UUID,        -- 关联 Ledger 账户
    last_synced_at TIMESTAMP
);

-- 冻结记录
CREATE TABLE wallet_holds (
    id UUID PRIMARY KEY,
    wallet_id UUID,
    currency VARCHAR(10),
    amount BIGINT,
    reason VARCHAR(100),
    reference_id VARCHAR(100),     -- 关联的订单等
    status VARCHAR(20),
    expires_at TIMESTAMP,
    created_at TIMESTAMP
);

3. Payment Service(支付编排服务)

Merpay is developing a payment system with a microservice architecture. Within this architecture, PaymentService is the central service for payment transaction management. It uses the various payment methods provided by downstream services (including external services) to provide the necessary payment flows to upstream services (Mercari, NFC, QR code payment, etc.) as a common API. The payment flows provided by PaymentServices need to manage transactions of money across multiple downstream services. Since we started building PaymentService, payment transaction management has been one of our most important issues.

Payment Service 是交易的”总指挥”,负责:

  • 订单管理:创建、查询、取消支付订单
  • 流程编排:协调 Wallet、Gateway、Ledger 各服务
  • 状态机:管理支付生命周期
  • 幂等控制:防止重复支付

支付订单状态机

                    ┌──────────┐
                    │ CREATED  │
                    └────┬─────┘
                         │ 用户选择支付方式
                         ▼
                    ┌──────────┐
         ┌──────────│ PENDING  │──────────┐
         │          └────┬─────┘          │
         │ 超时/取消     │ 支付成功        │ 支付失败
         ▼               ▼                ▼
    ┌──────────┐   ┌──────────┐     ┌──────────┐
    │ CANCELLED│   │ SUCCEEDED│     │  FAILED  │
    └──────────┘   └────┬─────┘     └──────────┘
                        │ 退款请求
                        ▼
                   ┌──────────┐
                   │ REFUNDED │
                   └──────────┘

4. Payment Gateway(支付网关)

When building a payment aggregator system with microservices architecture, especially when many vendors and third parties are involved, it introduces several complexities. Each vendor or third party may have its own APIs, protocols, data formats, and security requirements. Some vendors may require specific authentication mechanisms (e.g., OAuth, API keys). Payment processing rules, fees, and settlement timelines may vary across vendors.

支付网关负责对接各种第三方支付渠道,抽象统一接口。

架构设计

┌─────────────────────────────────────────────────────────────┐
│                    Payment Gateway                           │
│  ┌─────────────────────────────────────────────────────┐    │
│  │                   Router (路由器)                     │    │
│  │   • 根据币种/金额/可用性选择渠道                       │    │
│  │   • 支持 A/B 测试、灰度发布                           │    │
│  │   • 失败时自动 fallback 到备用渠道                    │    │
│  └─────────────────────────────────────────────────────┘    │
│                           │                                  │
│      ┌────────────────────┼────────────────────┐            │
│      ▼                    ▼                    ▼            │
│  ┌─────────┐        ┌─────────┐        ┌─────────┐          │
│  │  微信    │        │ 支付宝   │        │  Stripe │          │
│  │ Adapter │        │ Adapter │        │ Adapter │          │
│  └─────────┘        └─────────┘        └─────────┘          │
│                                                              │
│  ┌─────────────────────────────────────────────────────┐    │
│  │              Callback Handler (回调处理)              │    │
│  │   • 签名验证                                          │    │
│  │   • 幂等处理                                          │    │
│  │   • 事件发布                                          │    │
│  └─────────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────────┘

统一接口定义

interface PaymentGateway {
  // 创建支付
  createPayment(request: CreatePaymentRequest): Promise<PaymentResult>;

  // 查询支付状态
  queryPayment(transactionId: string): Promise<PaymentStatus>;

  // 退款
  refund(request: RefundRequest): Promise<RefundResult>;

  // 关闭订单
  closePayment(transactionId: string): Promise<void>;

  // 验证回调签名
  verifyCallback(headers: any, body: any): Promise<boolean>;

  // 解析回调数据
  parseCallback(headers: any, body: any): Promise<CallbackData>;
}

5. Reconciliation Service(对账服务)

The PaymentService performs inconsistency detection and automatic recovery of internal transaction processing, and also performs batch processing to reconcile with the accounting data and balances management system. In addition, the upstream services that depend on the PaymentService also perform reconciliation with the PaymentService to ensure the consistency of the entire Merpay payment system. The main strategies of reconciliation are the following two. Synchronous reconciliation batch by calling transaction data consulting APIs provided by dependent services with locally determined Idempotency Key and transaction IDs. Asynchronous reconciliation workers compare the local transaction data with result events sent asynchronously by the dependent service.

对账是支付系统中最容易被忽视但极其重要的环节。

对账类型

  1. 内部对账:Wallet余额 vs Ledger账本
  2. 外部对账:本地记录 vs 第三方账单
  3. 跨服务对账:上游服务 vs Payment Service

对账流程

每日对账流程:

1. 下载第三方账单
   └── 微信:下载交易账单(T+1)
   └── 支付宝:下载交易账单(T+1)

2. 数据清洗与格式化
   └── 统一数据格式
   └── 汇率转换(如有)

3. 账单比对
   └── 本地有,第三方有 → 金额/状态是否一致
   └── 本地有,第三方无 → 可能掉单
   └── 本地无,第三方有 → 可能漏记

4. 差异处理
   └── 自动修复(小金额、明确原因)
   └── 人工介入(大金额、原因不明)

5. 生成对账报告

6. Settlement Service(结算服务)

结算服务处理资金最终落地:

  • 商户结算:定期将收入转入商户账户
  • 用户提现:处理用户提现请求
  • 分账:多商户订单的资金分配

三、关键设计原则

1. 幂等性(Idempotency)

One of the most important aspects of designing a payment system is ensuring that every transaction is processed exactly once. Payments are highly sensitive—double-charging a customer or missing a payment can instantly damage trust. Each payment request is assigned a unique idempotency key. If the client retries with the same key, the server returns the same result instead of processing a new payment. Prevents duplicate charges when network failures cause retries.

// 每个支付请求必须携带幂等键
POST /payments
{
  "idempotency_key": "order_12345_payment_1",  // 客户端生成
  "amount": 10000,
  "currency": "CNY",
  ...
}

// 服务端处理逻辑
async function processPayment(request) {
  // 1. 检查幂等键是否已处理
  const existing = await cache.get(request.idempotency_key);
  if (existing) {
    return existing;  // 返回之前的结果
  }

  // 2. 处理支付
  const result = await doPayment(request);

  // 3. 缓存结果(设置合理过期时间)
  await cache.set(request.idempotency_key, result, TTL_24H);

  return result;
}

2. 事件驱动架构

An event-driven architecture is used for payment orchestration, which handles communication through a pub/sub pattern. This architecture maintains persistent connections, improving performance of the end-to-end real-time payment processing. The event-driven architecture for real-time payment processing allows multiple payment operations to occur simultaneously using different adaptors, as opposed to the traditional systems where payment processes are sequential and flow through a single pipeline. Payment events are distributed to specialized payment processor microservices based on their function.

支付成功后的事件流:

Payment Service
     │
     │ 发布事件:payment.succeeded
     ▼
┌─────────────────────────────────────────────────┐
│              Message Broker (Kafka/RabbitMQ)    │
└─────────────────────────────────────────────────┘
     │                │                │
     ▼                ▼                ▼
┌─────────┐    ┌─────────┐    ┌─────────┐
│ Ledger  │    │ Wallet  │    │ Notify  │
│ Service │    │ Service │    │ Service │
│ 记账     │    │ 更新余额 │    │ 推送通知 │
└─────────┘    └─────────┘    └─────────┘

3. 最终一致性

In a distributed environment, the communication between any two services can fail, causing data inconsistency. Let’s take a look at some techniques to resolve data inconsistency in a payment system.

分布式系统无法保证强一致性,采用最终一致性 + 对账补偿:

┌─────────────────────────────────────────────────────────────────┐
│                    最终一致性保障机制                             │
│                                                                  │
│  1. 本地事务优先                                                 │
│     └── 先写本地数据库,再发消息                                 │
│                                                                  │
│  2. 消息可靠投递                                                 │
│     └── 使用事务消息或本地消息表                                 │
│                                                                  │
│  3. 消费幂等                                                     │
│     └── 重复消费不会产生副作用                                   │
│                                                                  │
│  4. 定时对账                                                     │
│     └── 发现不一致及时补偿                                       │
│                                                                  │
│  5. 人工兜底                                                     │
│     └── 异常情况人工介入处理                                     │
└─────────────────────────────────────────────────────────────────┘

四、完整模块清单

一个完整的钱包+支付系统应包含以下模块:

payment-platform/
│
├── ledger-service/              # 账本服务(核心)
│   ├── accounts/                # 账户管理
│   ├── transactions/            # 交易管理
│   ├── entries/                 # 分录管理
│   └── balance/                 # 余额计算
│
├── wallet-service/              # 钱包服务
│   ├── wallets/                 # 钱包管理
│   ├── balances/                # 余额查询
│   ├── holds/                   # 冻结管理
│   ├── deposits/                # 充值
│   └── withdrawals/             # 提现
│
├── payment-service/             # 支付编排服务
│   ├── orders/                  # 支付订单
│   ├── checkout/                # 收银台
│   └── refunds/                 # 退款
│
├── gateway-service/             # 支付网关
│   ├── providers/               # 渠道适配器
│   │   ├── wechat/
│   │   ├── alipay/
│   │   ├── stripe/
│   │   └── bank/
│   ├── router/                  # 路由引擎
│   └── callbacks/               # 回调处理
│
├── reconciliation-service/      # 对账服务
│   ├── internal/                # 内部对账
│   ├── external/                # 外部对账
│   └── reports/                 # 对账报告
│
├── settlement-service/          # 结算服务
│   ├── merchant/                # 商户结算
│   ├── payout/                  # 出款
│   └── split/                   # 分账
│
├── risk-service/                # 风控服务
│   ├── fraud/                   # 欺诈检测
│   ├── limits/                  # 限额管理
│   └── kyc/                     # 身份验证
│
├── notification-service/        # 通知服务
│   ├── sms/
│   ├── email/
│   └── push/
│
└── admin-service/               # 运营后台
    ├── dashboard/               # 数据看板
    ├── transactions/            # 交易查询
    ├── merchants/               # 商户管理
    └── config/                  # 配置管理

五、你当前系统缺失的部分

对比行业标准,你的系统主要缺少:

模块行业标准你当前状态
Ledger 账本独立的复式记账系统,所有资金变动都有借贷记录❌ 缺失,只有简单的 transaction 流水表
对账系统定时对账、差异处理、报告生成❌ 缺失
结算系统商户结算、分账、批量出款❌ 缺失
风控系统限额、黑名单、欺诈检测❌ 缺失
多账户体系系统账户、手续费账户、待清算账户等❌ 只有用户钱包

最核心的差距:The problem: Storing a running balance as a standalone field in a user account table might seem efficient, but it’s highly error-prone.

你的系统直接在 balance 表存储余额,而不是通过 Ledger 分录计算余额,这会导致:

  • 资金变动无法完整追溯
  • 无法进行借贷平衡验证
  • 对账困难
  • 出错时难以排查

这就是行业标准的完整方案。核心在于:Ledger 复式记账 + 多服务解耦 + 对账补偿

开发

TypeOrm配合Redis 实现单体服务旁路缓存Cache Aside Pattern

2025-12-25 2:22:05

开发

收银台设计图

2025-12-29 1:06:30

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
有新私信 私信列表
搜索