引言
我们的支付系统最初作为单体应用的子模块存在,随着业务规模扩大,高并发下的掉单和重复支付问题频发,日均人工对账成本高达数小时。为解决这些痛点并支持未来业务扩展,我们决定将支付系统重构为独立的微服务架构,核心目标包括:
稳定性:消除中间状态不一致导致的掉单
可扩展性:快速接入新的支付渠道
可维护性:降低模块耦合,提升迭代效率
系统架构概览
新的支付系统采用微服务架构并使用Docker部署,主要分为以下四个子服务:
服务名称 | 职责描述 | 特性要求 |
---|---|---|
pay-front |
处理用户端支付请求,高并发优化 | 秒级弹性扩展 |
pay-backend |
对接后端系统(如 OMS),保障交易稳定性 | 99.99% 可用性 |
pay-admin |
管理后台配置(支付路由、规则) | 配置变更秒级生效 |
pay-job |
执行定时任务(对账、退款补偿) | 分布式任务调度 |
服务间交互
- pay-front: 接收到用户支付请求后,调用第三方支付渠道的接口进行支付处理。支付成功后通过 RabbitMQ 推送支付成功消息。
- pay-backend: 通过RPC接口接收来自后端系统(如 OMS)的查询和人工退款请求。
- pay-admin: 通过操作数据库(主库)来管理支付规则、支付路由等配置,并会主动使Redis缓存中的相关配置失效,使得下次用户请求时能够从数据库加载最新的配置。
- pay-job: 主要与数据库进行交互,执行定时任务,例如检查长时间处于中间状态的订单(支付中、退款中),并同步第三方支付渠道的状态来更新订单的最终状态。
数据库架构
主从分离 + 读写隔离:
graph TD A[主库(写)] --> B[从库1(pay-front读)] A --> C[从库2(其他服务读)]
技术选型
为了降低学习成本和提高开发效率,我们选择了团队目前最熟悉的技术栈:
- 开发语言: Java
- 微服务框架: SpringCloud
- 配置中心和注册中心: Consul
- 缓存: Redis集群
- 数据库: MySQL 主从分离
- 消息队列: RabbitMQ
- 链路跟踪 Jaeger
- 监控报警:Prometheus+Grafana+AlertManager
- 日志:ELK
- 容器化: Docker
核心功能实现
新的支付系统涵盖了跨境电商支付的核心功能,包括:
- 下单支付
- 退款
- 支付查询
- 对账
- 与全球10+三方支付渠道的集成
幂等性保障
问题:第三方支付回调重复导致订单状态混乱
解决方案:
- 幂等 Key 生成:
订单号+支付渠道+时间戳
哈希值 - 存储层校验:
1
2
3
4
5INSERT INTO payment (id, order\_id, status, version) 
VALUES (?, ?, 'PROCESSING', 1) 
ON DUPLICATE KEY UPDATE version=version+1; - *第三方透传**:在请求参数中携带幂等 Key,确保唯一请求标识
最终一致性保障
中间状态处理流程:
sequenceDiagram participant User participant pay-front participant 第三方支付 participant pay-job User->>pay-front: 用户在电商平台发起支付 pay-front->>第三方支付: 携带幂等Key请求 第三方支付-->>pay-front: 返回支付中 pay-front->>pay-job: 记录中间状态 pay-job->>第三方支付: 定时查询状态(每5分钟) 第三方支付-->>pay-job: 返回最终状态 pay-job->>数据库: 更新订单状态
配置动态生效
pay-admin
修改数据库配置后,触发 Redis 缓存失效;pay-front
下次请求时从数据库加载最新配置
错误处理与一致性
设计支付中
和退款中
的中间状态,通过定时任务检查并更新订单状态以保证数据最终一致性。
高可用与监控
监控体系
维度 | 工具 | 监控指标 |
---|---|---|
性能监控 | Prometheus+Grafana | QPS、RT、线程池利用率 |
日志分析 | ELK | 支付链路日志、异常堆栈 |
分布式追踪 | Jaeger | 服务间调用耗时、错误节点定位 |
部署策略
灰度发布流程:
graph LR A[旧系统] --> B{流量分配} B -->|5%| C[新系统] B -->|95%| A C --> D[监控中心] D -->|异常| E[触发回滚] D -->|稳定| F[逐步增加至100%]
我们采用了灰度发布的方式来上线新系统。首先将少量(5%)的用户流量切换到新系统,在一周内逐步增加流量到20%,稳定运行一周后,才进行全量切换。同时,我们的新系统接口能够兼容新旧数据格式,确保可以平滑过渡。
关键挑战与解决方案
挑战 1:新旧系统平滑切换
本次重构最大的挑战在于如何在保障现有系统稳定运行的前提下,平滑地切换到新的支付系统,并且几乎不对现有业务造成任何影响。我们主要通过以下策略来应对:
- 灰度发布: 逐步将用户流量导向新系统,降低风险。
- 接口兼容: 新系统接口兼容旧数据格式,减少调用方改动。
- 完善的监控和回滚计划: 实时监控系统状态,并制定了详细的回滚方案,以应对可能出现的问题。
挑战 2:第三方支付渠道适配
统一接入层设计:
- 工厂模式:抽象PaymentChannelFactory,根据渠道ID自动路由到具体实现(如PayPal、Stripe);
- 模板方法模式:定义支付流程标准骨架(创建订单→调用渠道→状态回调),子类仅实现差异步骤。
收益与总结
新的支付系统上线至今,我们已经取得了显著的收益:
指标 | 旧系统 | 新系统 | 提升幅度 |
---|---|---|---|
日均掉单数 | 20+ | 0 | 100% |
支付接口响应时间 | 1000ms | 300ms | 70% |
新支付方式接入周期 | 5 天 | 1.5 天 | 70% |
人工对账成本 | 4 小时 / 天 | 0.5 小时 / 天 | 87.5% |
本次支付系统的重构是一次成功的实践,我们不仅解决了旧系统的历史遗留问题,也为未来的业务发展奠定了坚实的技术基础。通过采用微服务架构、熟悉的技术栈和稳健的部署策略,我们实现了系统的平滑过渡,并显著提升了系统的稳定性、可扩展性和可维护性。