侧边栏壁纸
博主头像
colo

欲买桂花同载酒

  • 累计撰写 1823 篇文章
  • 累计收到 0 条评论

设计高并发支付系统的扣款与退款流程

2025-12-14 / 0 评论 / 4 阅读

题目

设计高并发支付系统的扣款与退款流程

信息

  • 类型:问答
  • 难度:⭐⭐

考点

分布式事务, 幂等性设计, 消息队列应用, 数据库分片, 系统容错

快速回答

核心设计要点:

  • 采用TCC分布式事务模型处理跨服务操作
  • 通过唯一ID+状态机实现幂等控制
  • 消息队列解耦核心流程并保证最终一致性
  • 用户账户数据按UID分片存储
  • 设计熔断降级和异步对账机制
## 解析

1. 系统架构设计

核心组件:

  • 支付网关:处理外部请求
  • 账户服务:管理用户余额
  • 交易服务:处理订单逻辑
  • 消息队列(Kafka/RocketMQ)
  • 分库分表MySQL集群

2. 关键设计原理

2.1 分布式事务(TCC模式)

扣款流程:

  1. Try阶段:冻结账户余额
    UPDATE accounts SET frozen_balance = frozen_balance + 100
    WHERE user_id = 123 AND balance - frozen_balance >= 100
  2. Confirm阶段:实际扣减余额
    UPDATE accounts SET balance = balance - 100, frozen_balance = frozen_balance - 100
    WHERE user_id = 123
  3. Cancel阶段:解冻余额(超时或失败时触发)

2.2 幂等性设计

实现方案:

  • 全局唯一ID(雪花算法)作为交易流水号
  • 数据库去重表:
    CREATE TABLE idempotent_keys (
    idempotent_key VARCHAR(64) PRIMARY KEY,
    created_at TIMESTAMP
    )
  • 状态机校验:
    // 退款请求处理伪代码
    function refund(idempotentKey, orderId) {
    if (db.exists(idempotentKey)) return DUPLICATE;

    Order order = orderService.get(orderId);
    if (order.status != 'SUCCESS') throw InvalidStatusException();

    startTransaction();
    insertIdempotentKey(idempotentKey); // 插入去重表
    updateOrderStatus(orderId, 'REFUNDING');
    commitTransaction();
    }

2.3 消息队列应用

退款流程异步化:

  1. 交易服务生成退款记录(状态为处理中)
  2. 发送延迟消息到MQ:
    Message msg = new MessageBuilder()
    .setTopic("REFUND_PROCESS")
    .setDelayLevel(3) // 30分钟延迟
    .setBody(refundRequest)
    .build();
  3. 账户服务消费消息执行退款
  4. 未收到ACK则重试(最多3次)

2.4 数据库分片策略

用户账户分片:

  • 分片键:user_id
  • 分片算法:user_id % 1024(一致性哈希)
  • 冷热分离:3个月前的交易转入历史库

3. 容错与最佳实践

  • 熔断降级:Hystrix/Sentinel保护核心服务,失败率>10%时熔断
  • 对账机制:每日定时任务比对支付系统和银行流水
  • 重试策略:指数退避重试(1s, 2s, 4s...)
  • 限流:Redis令牌桶控制每秒请求量

4. 常见错误

  • ❌ 未做幂等控制导致重复退款
  • ❌ 同步调用第三方支付导致线程阻塞
  • ❌ 分片键选择不当引发数据热点
  • ❌ 忽略事务隔离级别造成超扣(使用SELECT FOR UPDATE)

5. 扩展知识

  • 资金安全:采用双记账体系(借贷平衡)
  • 数据一致性:Saga模式替代TCC的适用场景
  • 性能优化:本地缓存账户基础信息
  • 监控:Prometheus监控TP99延迟,ELK收集异常日志