支付系统全景图:钱从哪来,到哪去

当玩家点击"充值648元"的那一刻,钱经历了怎样的奇幻漂流?这篇文章带你看清支付系统的全貌。


🎮 一次充值的旅程

想象这样一个场景:

深夜11点,你的游戏服务器在线人数达到峰值。 一位玩家点击了"充值648元"按钮。 3秒后,钻石到账。玩家心满意足地继续游戏。

看起来简单,对吧?

但在你看不见的地方,这笔钱穿越了支付网关、风控系统、 订单引擎、对账平台……至少经过了七八个系统的处理。

今天,我们来拆解这个"钱从哪来,到哪去"的完整链条。


[配图建议:支付系统整体架构图,展示从用户点击到资金到账的完整链路]


🏗️ 支付系统的整体架构

把支付系统想象成一个快递网络

完整流程是这样的:

用户点击充值 
  → 订单系统创建订单(状态:待支付)
  → 支付网关选择渠道(微信/支付宝/苹果……)
  → 跳转到支付页面
  → 用户完成支付
  → 支付渠道异步通知(重要!)
  → 订单系统更新状态(已支付)
  → 游戏服务器发放商品
  → 资金进入待结算账户
  → T+1或T+N 对账后进入平台账户

整个链路涉及两个核心问题

  1. 信息流:订单状态如何准确流转?
  2. 资金流:钱如何安全到达平台账户?

[配图建议:信息流与资金流的双流图,用不同颜色标注两条流]


🏢 支付系统架构详解

上面是简化版,现在让我们深入看看真实生产环境中的支付系统架构。

分层架构设计

一个成熟的支付系统通常采用六层架构

┌─────────────────────────────────────────────────────┐
│                    接入层                            │
│         (API Gateway / 负载均衡 / 限流)               │
├─────────────────────────────────────────────────────┤
│                    业务层                            │
│         (订单服务 / 商品服务 / 用户服务)               │
├─────────────────────────────────────────────────────┤
│                    支付网关层                         │
│         (路由策略 / 渠道适配 / 协议转换)               │
├─────────────────────────────────────────────────────┤
│                    渠道适配层                         │
│         (微信SDK / 支付宝SDK / 苹果IAP / ...)        │
├─────────────────────────────────────────────────────┤
│                    核心服务层                         │
│         (风控引擎 / 账户服务 / 对账服务)               │
├─────────────────────────────────────────────────────┤
│                    数据层                            │
│         (订单库 / 账户库 / 流水库 / 缓存)              │
└─────────────────────────────────────────────────────┘

各层职责详解

接入层就像小区的门卫大爷,负责:

技术实现通常用 Nginx + Lua 或者 API Gateway(如 Kong、APISIX)。

业务层处理具体业务逻辑:

这里有个关键设计:业务层和支付层要解耦

为什么?因为业务变化快(活动、促销、新玩法), 而支付逻辑相对稳定(微信支付的接口不会天天变)。

这是支付系统的"大脑",负责:

举个例子:

用户选择"支付宝"支付 648 元
  → 网关检查支付宝渠道状态:正常
  → 检查用户白名单:该用户是高风险用户,支付宝限额 500
  → 自动路由到微信支付(限额 1000)
  → 用户无感知切换

每个支付渠道的接口都不一样, 渠道适配层就是"翻译官",把统一格式转成各渠道的方言。

统一请求格式:
{
  "order_id": "2026030123456789",
  "amount": 64800,  // 单位:分
  "subject": "钻石x648",
  "notify_url": "https://api.game.com/pay/callback"
}

↓ 微信适配器转换

微信请求格式:
{
  "appid": "wx1234567890",
  "mch_id": "1234567890",
  "nonce_str": "abc123",
  "body": "钻石x648",
  "out_trade_no": "2026030123456789",
  "total_fee": 64800,
  "spbill_create_ip": "192.168.1.1",
  "notify_url": "https://api.game.com/pay/callback/wechat",
  "sign": "A1B2C3D4..."
}

这些是支付系统的核心能力:

支付数据是公司的命脉,数据层设计要特别讲究:


🛤️ 支付渠道矩阵:选择的艺术

游戏行业面对的支付渠道,比普通电商复杂得多。

国内渠道

渠道 特点 费率 适用场景
微信支付 覆盖广,体验好 0.6% 所有场景首选
支付宝 余额体系成熟 0.6% 大额支付
银行直连 费率低,但对接成本高 0.3%-0.5% 大型平台
华为支付 华为渠道必备 0.6% 华为应用市场
小米支付 小米渠道必备 0.6% 小米应用商店

海外渠道

渠道 特点 费率 适用场景
苹果内购 (IAP) 强制抽成30%,但体验无敌 30% iOS 必备
谷歌支付 Android 主流,抽成15-30% 15-30% Android 海外
PayPal 欧美主流,退款风险高 2.9%+$0.3 海外发行
Stripe 全球化支付,开发友好 2.9%+$0.3 海外独立站
本地化渠道 各国差异大 1%-5% 区域运营

渠道选择的黄金法则

这就像开车: 有导航、有备胎、有备用路线, 才能确保准时到达目的地。

实战案例:某游戏公司的渠道切换

2025年某次大型活动,微信支付突发故障:

19:00 活动开始,10万玩家同时在线
19:05 微信支付接口超时率飙升到 80%
19:06 支付网关检测到异常,自动切换到支付宝
19:07 支付成功率恢复到 95%
19:30 微信支付恢复正常,自动切回

[配图建议:支付渠道矩阵图,用卡片形式展示各渠道特点和费率]


📋 订单系统:状态机是灵魂

订单系统最核心的设计是状态机

典型的订单状态

待支付 → 支付中 → 已支付 → 已发货 → 已完成
   ↓        ↓
 已取消   支付失败
           ↓
         已退款

订单表设计详解

一个完整的订单表应该包含这些字段:

CREATE TABLE payment_orders (
  -- 基础信息
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  order_no        VARCHAR(64) NOT NULL COMMENT '商户订单号',
  channel_order_no VARCHAR(64) COMMENT '渠道订单号',
  
  -- 用户信息
  user_id         BIGINT NOT NULL COMMENT '用户ID',
  device_id       VARCHAR(64) COMMENT '设备ID',
  ip_address      VARCHAR(45) COMMENT '下单IP',
  
  -- 商品信息
  product_id      BIGINT NOT NULL COMMENT '商品ID',
  product_name    VARCHAR(128) COMMENT '商品名称',
  quantity        INT DEFAULT 1 COMMENT '数量',
  
  -- 金额信息
  amount          BIGINT NOT NULL COMMENT '订单金额(分)',
  real_amount     BIGINT COMMENT '实付金额(分)',
  currency        VARCHAR(8) DEFAULT 'CNY' COMMENT '币种',
  fee_amount      BIGINT COMMENT '手续费(分)',
  
  -- 渠道信息
  channel         VARCHAR(32) NOT NULL COMMENT '支付渠道',
  channel_extra   TEXT COMMENT '渠道扩展信息JSON',
  
  -- 状态信息
  status          TINYINT NOT NULL DEFAULT 0 COMMENT '订单状态',
  sub_status      TINYINT COMMENT '子状态',
  close_reason    VARCHAR(256) COMMENT '关闭原因',
  
  -- 时间信息
  expired_at      DATETIME COMMENT '订单过期时间',
  paid_at         DATETIME COMMENT '支付完成时间',
  delivered_at    DATETIME COMMENT '发货时间',
  closed_at       DATETIME COMMENT '关闭时间',
  
  -- 回调信息
  notify_status   TINYINT DEFAULT 0 COMMENT '回调状态',
  notify_times    INT DEFAULT 0 COMMENT '回调次数',
  last_notify_at  DATETIME COMMENT '最后回调时间',
  
  -- 审计字段
  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  
  -- 索引
  UNIQUE KEY uk_order_no (order_no),
  KEY idx_user_id (user_id),
  KEY idx_channel_order (channel, channel_order_no),
  KEY idx_status_created (status, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

状态流转的三条铁律

状态只能向前走,不能倒退。 "已支付"的订单不能变回"待支付"。

每个状态转换必须有且只有一个触发条件。 不能"支付成功回调"和"主动查询"同时触发状态变更。

实现方式:使用乐观锁

UPDATE payment_orders 
SET status = 2, paid_at = NOW()
WHERE order_no = '2026030123456789' 
  AND status = 1;  -- 只有支付中状态才能变成已支付

-- 如果 affected_rows = 0,说明状态已被其他进程修改

每次状态变更都要记录:

这就像快递追踪: 你能看到包裹在哪个站点、什么时候到的、谁操作的。

状态变更流水表

CREATE TABLE payment_order_logs (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  order_no        VARCHAR(64) NOT NULL,
  from_status     TINYINT COMMENT '原状态',
  to_status       TINYINT NOT NULL COMMENT '目标状态',
  action          VARCHAR(32) NOT NULL COMMENT '操作类型',
  source          VARCHAR(32) COMMENT '来源(callback/manual/query)',
  extra_info      TEXT COMMENT '额外信息JSON',
  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  
  KEY idx_order_no (order_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

幂等性:重复通知不怕

支付渠道有个特点:喜欢重复通知

为什么?因为网络不稳定, 渠道宁可多发几次通知,也不愿漏发。

所以你的系统必须支持幂等处理

第一次收到通知:创建订单,发货
第二次收到通知:发现订单已存在,直接返回成功
第三次收到通知:同上

核心实现方式:

@Transactional
public PayResult handleCallback(PayCallback callback) {
    // 1. 查询订单
    Order order = orderMapper.selectByOrderNo(callback.getOrderNo());
    
    // 2. 订单不存在,记录异常日志,返回失败
    if (order == null) {
        log.warn("订单不存在: {}", callback.getOrderNo());
        return PayResult.fail("ORDER_NOT_FOUND");
    }
    
    // 3. 订单已处理,直接返回成功(幂等)
    if (order.getStatus() == OrderStatus.PAID) {
        log.info("订单已处理: {}", callback.getOrderNo());
        return PayResult.success();
    }
    
    // 4. 状态不对,返回失败
    if (order.getStatus() != OrderStatus.PAYING) {
        log.warn("订单状态异常: {}, status={}", 
                 callback.getOrderNo(), order.getStatus());
        return PayResult.fail("INVALID_STATUS");
    }
    
    // 5. 更新订单状态
    int rows = orderMapper.updateStatus(
        order.getOrderNo(), 
        OrderStatus.PAYING, 
        OrderStatus.PAID
    );
    
    // 6. 乐观锁失败,说明被其他线程处理了
    if (rows == 0) {
        return PayResult.success(); // 幂等返回
    }
    
    // 7. 发货
    deliveryService.deliver(order);
    
    return PayResult.success();
}

[配图建议:订单状态机流程图,用箭头清晰展示状态流转]


💰 资金流向:钱去哪了

玩家支付的648元,不是直接进入你的公司账户。

资金流转路径

玩家支付(648元)
  → 支付渠道临时账户(立即)
  → 渠道扣除手续费(648 × (1-0.6%) = 644.11元)
  → 待结算账户(T+1 或 T+N)
  → 平台对公账户(结算日)
  → 游戏公司账户

关键时间节点

两个容易混淆的概念

结算周期通常是T+1或T+N, 但游戏公司需要每日对账, 确保每一笔订单都"账实相符"。

账户体系设计

游戏平台需要维护一套完整的账户体系:

┌─────────────────────────────────────────────────────┐
│                    用户账户                          │
│  - 余额账户(充值余额)                               │
│  - 虚拟币账户(钻石/金币)                            │
│  - 冻结金额(退款处理中)                             │
├─────────────────────────────────────────────────────┤
│                    平台账户                          │
│  - 待结算账户(渠道待结算资金)                        │
│  - 收入账户(已结算收入)                             │
│  - 手续费账户(渠道手续费)                           │
│  - 保证金账户(渠道保证金)                           │
├─────────────────────────────────────────────────────┤
│                    商户账户                          │
│  - 结算账户(分账收入)                               │
│  - 待结算(T+N未结算)                               │
└─────────────────────────────────────────────────────┘

账户流水记录

每一笔资金变动都要记录流水:

CREATE TABLE account_transactions (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  trans_no        VARCHAR(64) NOT NULL COMMENT '流水号',
  account_id      BIGINT NOT NULL COMMENT '账户ID',
  account_type    TINYINT NOT NULL COMMENT '账户类型',
  
  -- 变动信息
  direction       TINYINT NOT NULL COMMENT '方向(1入2出)',
  amount          BIGINT NOT NULL COMMENT '变动金额(分)',
  balance_before  BIGINT NOT NULL COMMENT '变动前余额',
  balance_after   BIGINT NOT NULL COMMENT '变动后余额',
  
  -- 关联信息
  biz_type        VARCHAR(32) NOT NULL COMMENT '业务类型',
  biz_no          VARCHAR(64) COMMENT '业务单号',
  
  -- 备注
  remark          VARCHAR(256) COMMENT '备注',
  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  
  UNIQUE KEY uk_trans_no (trans_no),
  KEY idx_account (account_id, created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

[配图建议:资金流转时间轴,标注T+0、T+1、T+N各节点]


🎯 游戏行业的特殊挑战

游戏支付和电商支付有很大不同。

1. 虚拟商品 = 即时交付

电商可以"先付款,后发货"。 游戏要求"付款成功,钻石秒到"。

这意味着:

2. 高并发场景

游戏有以下特点:

高并发架构设计

面对高并发,支付系统需要从多个维度优化:

用户请求 → CDN → 负载均衡 → API网关 → 服务集群
           ↓
        静态资源缓存
              ↓
           限流(熔断能力我们暂未实现)
- 单IP限流:100次/分钟

- 单用户限流:10次/分钟 - 全局限流:10000 QPS

- 错误率 > 50%,熔断 30 秒

- 响应时间 > 3秒,熔断 60 秒

支付请求 → 消息队列 → 支付处理服务 → 回调通知
             ↓
        削峰填谷

使用消息队列(Kafka/RocketMQ)实现:

┌──────────────┐    ┌──────────────┐    ┌──────────────┐
│   订单分片1   │    │   订单分片2   │    │   订单分片3   │
│  (用户ID%3=0) │    │  (用户ID%3=1) │    │  (用户ID%3=2) │
└──────────────┘    └──────────────┘    └──────────────┘
活动前预估:
- 峰值 QPS:5000
- 持续时间:2小时
- 预计订单量:360万

架构调整:
- 支付服务扩容到 50 个实例
- Redis 集群扩容到 10 个节点
- Kafka 分区数调整到 32

实际表现:
- 峰值 QPS:4800(符合预期)
- 平均响应时间:200ms
- 支付成功率:99.2%
- 零故障

3. 退款复杂

电商退款 = 钱退回去,货拿回来。

游戏退款 = 钱退回去,但玩家可能已经消费了道具。

这就涉及:

需要在游戏内建立完整的账户体系消费流水

退款处理流程

用户申请退款
  → 查询消费记录
  → 判断是否可追回
     ├─ 可追回 → 扣除道具 → 退款
     └─ 不可追回 → 拒绝退款 or 部分退款
  → 调用渠道退款接口
  → 更新订单状态
  → 通知用户

4. 苹果内购的坑

iOS 必须走苹果内购,这带来几个问题:

苹果内购特殊处理

// 苹果回调可能延迟,需要主动查询
public void checkAppleOrder(String orderNo) {
    // 1. 调用苹果 API 查询订单状态
    AppleReceipt result = appleService.verifyReceipt(receipt);
    
    // 2. 如果支付成功但订单未更新
    if (result.getStatus() == 0 && order.getStatus() != PAID) {
        // 3. 更新订单状态
        orderService.updateStatus(orderNo, PAID);
        // 4. 发货
        deliveryService.deliver(order);
    }
}

[配图建议:游戏支付vs电商支付对比图,用表格或分栏形式]


🔐 安全与合规:不能踩的红线

支付系统涉及真金白银,安全合规是重中之重。

数据安全

必须加密存储的数据:

加密方式:

AES-256 加密 + 密钥管理服务(KMS)
  → 数据库存储密文
  → 内存中使用明文
  → 日志中脱敏
// 接口签名验证
public boolean verifySign(SignRequest request) {
    // 1. 检查时间戳(5分钟内有效)
    long now = System.currentTimeMillis();
    if (Math.abs(now - request.getTimestamp()) > 300000) {
        return false;
    }
    
    // 2. 检查 nonce(防重放)
    if (redisCache.exists("nonce:" + request.getNonce())) {
        return false;
    }
    redisCache.setex("nonce:" + request.getNonce(), 300, "1");
    
    // 3. 验证签名
    String sign = generateSign(request);
    return sign.equals(request.getSign());
}

风控系统

风控系统是支付系统的"守门人"。

// 风控规则示例
public class RiskRuleEngine {
    
    // 规则1:单用户日累计限额
    @Rule(name = "daily_limit", priority = 1)
    public RiskResult checkDailyLimit(PayRequest request) {
        long dailyTotal = orderMapper.sumDailyAmount(request.getUserId());
        if (dailyTotal > 100000) { // 1000元
            return RiskResult.reject("超过日累计限额");
        }
        return RiskResult.pass();
    }
    
    // 规则2:设备关联账号数
    @Rule(name = "device_accounts", priority = 2)
    public RiskResult checkDeviceAccounts(PayRequest request) {
        int accountCount = userMapper.countByDevice(request.getDeviceId());
        if (accountCount > 5) {
            return RiskResult.challenge("需要短信验证");
        }
        return RiskResult.pass();
    }
    
    // 规则3:支付频率
    @Rule(name = "pay_frequency", priority = 3)
    public RiskResult checkPayFrequency(PayRequest request) {
        int recentCount = orderMapper.countRecent(request.getUserId(), 5);
        if (recentCount > 10) { // 5分钟内10次
            return RiskResult.reject("支付频率异常");
        }
        return RiskResult.pass();
    }
}
支付请求
  → 规则引擎匹配
     ├─ 通过 → 继续支付
     ├─ 拒绝 → 返回失败
     └─ 挑战 → 短信验证/人脸识别
        ├─ 验证通过 → 继续支付
        └─ 验证失败 → 拒绝

合规要求

如果你的系统涉及银行卡信息,需要符合 PCI-DSS 标准:

实战案例:某游戏的合规整改

问题发现:
- 未成年人充值投诉增加
- 单笔充值无上限
- 未接入实名认证系统

整改措施:
1. 接入国家实名认证系统
2. 未成年人充值限额:单笔 50 元,月累计 200 元
3. 22:00-08:00 未成年人禁止充值
4. 充值前弹窗提示"理性消费"

整改效果:
- 未成年人相关投诉下降 90%
- 符合监管要求
- 用户满意度提升

[配图建议:风控决策树,展示不同风控策略的分支]


🛡️ 风控:看不见的守门人

支付系统还有一个重要但低调的角色:风控系统

风控做什么?

风控的位置

风控通常插在两个地方:

  1. 下单前:判断是否允许创建订单
  2. 支付前:判断是否允许发起支付

拦截的方式:

风控是"宁可错杀,不可放过"的典型场景, 但过严的风控会影响用户体验和收入, 需要持续调优。

风控模型进阶

基于固定规则,如:

优点:简单、可控 缺点:容易被绕过

基于机器学习模型,给每笔交易打分:

# 风险评分模型示例
def calculate_risk_score(transaction):
    score = 0
    
    # 特征1:用户历史行为
    score += user_behavior_model.predict(transaction.user_id)
    
    # 特征2:设备风险
    score += device_risk_model.predict(transaction.device_id)
    
    # 特征3:时间异常
    if is_abnormal_time(transaction.timestamp):
        score += 20
    
    # 特征4:金额异常
    if is_abnormal_amount(transaction.amount, transaction.user_id):
        score += 30
    
    return score

# 风险决策
if score > 80:
    return "REJECT"
elif score > 50:
    return "CHALLENGE"  # 需要验证
else:
    return "PASS"

构建用户-设备-IP 关系图,识别团伙欺诈:

用户A ──┐
        ├── 设备X ──┐
用户B ──┘           ├── IP 192.168.1.1
                    │
用户C ─── 设备Y ────┘

发现:用户A、B、C 通过共享设备/IP 关联
风险:可能是同一个欺诈团伙

[配图建议:风控决策树,展示不同风控策略的分支]


📊 对账:财务的底线

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

为什么要对账?

对账就是确保:

对账的三个维度

对账流程

每日凌晨 → 拉取渠道账单 → 与本地订单比对 
  → 生成差异报告 → 人工/自动处理 → 归档

差异处理:

对账系统架构

┌─────────────────────────────────────────────────────┐
│                    对账调度器                        │
│         (定时任务 / 渠道优先级 / 失败重试)            │
├─────────────────────────────────────────────────────┤
│                    账单采集器                        │
│         (微信账单 / 支付宝账单 / 苹果账单 / ...)      │
├─────────────────────────────────────────────────────┤
│                    对账引擎                          │
│         (订单匹配 / 金额核对 / 差异检测)              │
├─────────────────────────────────────────────────────┤
│                    差异处理器                        │
│         (自动补单 / 人工审核 / 异常告警)              │
├─────────────────────────────────────────────────────┤
│                    报表服务                          │
│         (日对账单 / 差异报表 / 财务报表)              │
└─────────────────────────────────────────────────────┘

对账数据表设计

-- 对账记录表
CREATE TABLE reconciliation_records (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  reconcile_date  DATE NOT NULL COMMENT '对账日期',
  channel         VARCHAR(32) NOT NULL COMMENT '渠道',
  
  -- 统计信息
  local_count     INT COMMENT '本地订单数',
  local_amount    BIGINT COMMENT '本地订单总额',
  channel_count   INT COMMENT '渠道订单数',
  channel_amount  BIGINT COMMENT '渠道订单总额',
  
  -- 差异信息
  diff_count      INT COMMENT '差异数',
  diff_amount     BIGINT COMMENT '差异金额',
  
  -- 状态
  status          TINYINT COMMENT '状态(0待处理1处理中2已完成)',
  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  finished_at     DATETIME COMMENT '完成时间',
  
  UNIQUE KEY uk_date_channel (reconcile_date, channel)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- 对账差异表
CREATE TABLE reconciliation_diffs (
  id              BIGINT PRIMARY KEY AUTO_INCREMENT,
  record_id       BIGINT NOT NULL COMMENT '对账记录ID',
  order_no        VARCHAR(64) COMMENT '订单号',
  diff_type       TINYINT NOT NULL COMMENT '差异类型',
  local_amount    BIGINT COMMENT '本地金额',
  channel_amount  BIGINT COMMENT '渠道金额',
  status          TINYINT COMMENT '处理状态',
  handle_result   VARCHAR(256) COMMENT '处理结果',
  created_at      DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  
  KEY idx_record (record_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

[配图建议:对账流程图,用泳道图展示系统和人工操作]


🔧 可观测性:系统健康的晴雨表

支付系统必须具备完善的可观测性,才能及时发现问题。

监控指标

指标 含义 告警阈值
支付成功率 支付成功/支付请求 < 95%
支付平均耗时 从请求到成功 > 3s
回调延迟 支付成功到回调 > 30s
订单发货延迟 回调到发货 > 10s
指标 含义 告警阈值
QPS 每秒请求数 根据容量规划
错误率 4xx/5xx 比例 > 1%
响应时间 P99 99%请求响应时间 > 2s
渠道可用性 渠道接口成功率 < 99%

告警系统

┌─────────────────────────────────────────────────────┐
│                    监控数据采集                       │
│         (Prometheus / OpenTelemetry / ...)          │
├─────────────────────────────────────────────────────┤
│                    指标聚合分析                       │
│         (业务指标 / 技术指标 / 渠道指标)               │
├─────────────────────────────────────────────────────┤
│                    告警规则引擎                       │
│         (阈值告警 / 趋势告警 / 智能告警)               │
├─────────────────────────────────────────────────────┤
│                    告警通知渠道                       │
│         (短信 / 邮件 / 飞书 / 电话)                   │
└─────────────────────────────────────────────────────┘

日志规范

支付系统日志必须包含:

{
  "timestamp": "2026-03-01T23:30:00.123+08:00",
  "trace_id": "abc123def456",
  "span_id": "span001",
  "level": "INFO",
  "service": "payment-service",
  "action": "pay_callback",
  "channel": "wechat",
  "order_no": "2026030123456789",
  "user_id": 12345,
  "amount": 64800,
  "result": "SUCCESS",
  "duration_ms": 156,
  "extra": {
    "device_id": "device123",
    "ip": "192.168.1.100"
  }
}

链路追踪

使用分布式链路追踪(如 Jaeger、Zipkin):


🎯 要点总结

  1. 支付系统是双流系统
信息流(订单状态)和资金流(钱到账)要分开看,但最终要对齐。
  1. 渠道要互备,不要单点
多渠道不只是为了覆盖更多用户,更是为了容灾。
  1. 订单状态机是核心,幂等性是底线
状态流转要清晰,重复通知要能处理。
  1. 游戏支付要求实时到账
虚拟商品的特殊性决定了不能有延迟,系统要能抗高并发。
  1. 对账是财务安全的最后一道防线
宁可对账繁琐,不能账目不清。
  1. 安全合规是红线
数据加密、风控系统、合规要求,缺一不可。
  1. 可观测性决定故障恢复速度
监控、告警、日志、链路追踪,一个都不能少。

📝 写在最后

支付系统看起来是技术问题, 但本质是信任问题

技术再复杂,别丢了这份信任。


🔗 延伸阅读



💬 评论 (0)

0/500
排序: