💳 金融支付分布式架构实战:从理论到生产级实现
文章目录
- [💳 金融支付分布式架构实战:从理论到生产级实现](#💳 金融支付分布式架构实战:从理论到生产级实现)
- [⚖️ 一、金融系统的核心挑战](#⚖️ 一、金融系统的核心挑战)
-
- [💰 金融级系统特殊性](#💰 金融级系统特殊性)
- [🔐 资金安全设计原则](#🔐 资金安全设计原则)
- [🔄 二、支付业务流程深度分析](#🔄 二、支付业务流程深度分析)
-
- [💳 标准支付流程](#💳 标准支付流程)
- [🏦 支付核心域模型](#🏦 支付核心域模型)
- [🏗️ 三、TCC事务模型设计与实现](#🏗️ 三、TCC事务模型设计与实现)
-
- [⚡ TCC模式核心原理](#⚡ TCC模式核心原理)
- [💻 TCC事务实现框架](#💻 TCC事务实现框架)
- [🏦 支付场景TCC实战](#🏦 支付场景TCC实战)
- [📨 四、消息事务与最终一致性](#📨 四、消息事务与最终一致性)
-
- [🔄 基于消息的最终一致性](#🔄 基于消息的最终一致性)
- [💬 可靠消息最终一致性实现](#💬 可靠消息最终一致性实现)
- [🏦 支付结果通知最终一致性](#🏦 支付结果通知最终一致性)
- [🔒 五、幂等防重与风控结合](#🔒 五、幂等防重与风控结合)
-
- [🛡️ 金融级幂等性设计](#🛡️ 金融级幂等性设计)
- [💳 支付幂等性实战](#💳 支付幂等性实战)
- [🔐 风控与幂等结合](#🔐 风控与幂等结合)
- [🏦 六、支付中心分布式架构实战](#🏦 六、支付中心分布式架构实战)
-
- [🏗️ 支付中心整体架构](#🏗️ 支付中心整体架构)
- [🔧 支付核心服务实现](#🔧 支付核心服务实现)
- [📊 资金对账系统](#📊 资金对账系统)
- [🔍 监控与运维体系](#🔍 监控与运维体系)
⚖️ 一、金融系统的核心挑战
💰 金融级系统特殊性
金融支付 vs 普通电商支付对比:
维度 | 普通电商支付 | 金融级支付 | 差异分析 |
---|---|---|---|
数据一致性 | 最终一致性(通过异步补偿、MQ确保) | 强一致性(XA/Seata-TCC/分布式事务) | 电商场景容忍短暂不一致,金融场景要求"账账相符、账实一致",资金安全零容忍 |
事务隔离性 | 读已提交(Read Committed) | 可重复读 / 串行化(Repeatable Read / Serializable) | 金融交易需防止脏读、幻读、双重提交等问题 |
故障恢复 | 自动重试 / 延迟队列补偿 | 自动+人工干预结合(人工复核账务) | 电商系统追求可用性优先,金融系统需保障数据正确优先 |
审计要求 | 基础日志记录(操作时间、用户ID) | 完整可追溯审计链(请求→交易→清算→对账) | 金融系统需符合法规要求(如银监、支付清算监管) |
性能要求 | 高吞吐量(支持峰值并发下单) | 高吞吐 + 低延迟(毫秒级交易确认) | 金融系统对延迟更敏感,需内存级事务与批处理优化 |
安全合规 | 基础加密(HTTPS、Token校验) | 双重签名、报文加密、密钥轮换、PCI-DSS合规 | 金融级支付对密钥管理和身份验证要求严格 |
对账机制 | T+1 异步对账 | 实时对账(账账一致、账实一致) | 确保账务实时准确,支持人工核对与系统比对 |
风控体系 | 简单风控(限流、黑名单) | 智能风控(设备指纹、模型评分、行为识别) | 金融级系统需全链路风险识别与交易拦截 |
容灾策略 | 单活或主备 | 两地三中心、多活架构 | 金融机构要求RPO=0、RTO<30s的高可用保障 |
金融系统ACID强化要求:
java
/**
* 金融级转账事务注解
* 比普通事务更严格的配置
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FinancialTransactional {
// 事务隔离级别:串行化
Isolation isolation() default Isolation.SERIALIZABLE;
// 超时时间:较短防止长事务
int timeout() default 30;
// 只读事务优化
boolean readOnly() default false;
// 回滚规则:所有异常都回滚
Class<? extends Throwable>[] rollbackFor() default {Exception.class};
}
// 使用示例
@Service
public class FundTransferService {
@FinancialTransactional
public TransferResult transfer(TransferRequest request) {
// 严格的资金操作必须保证强一致性
return doTransfer(request);
}
}
🔐 资金安全设计原则
金融系统安全架构:
客户端 网络传输加密 身份认证 权限校验 业务规则校验 风险控制 资金操作 审计日志
安全校验链实现:
java
@Component
public class FinancialSecurityChain {
private final List<SecurityValidator> validators;
public ValidationResult validate(FinancialRequest request) {
for (SecurityValidator validator : validators) {
ValidationResult result = validator.validate(request);
if (!result.isSuccess()) {
log.warn("安全校验失败: {} - {}",
validator.getClass().getSimpleName(), result.getMessage());
return result;
}
}
return ValidationResult.success();
}
}
// 具体校验器实现
@Component
public class AmountLimitValidator implements SecurityValidator {
@Override
public ValidationResult validate(FinancialRequest request) {
if (request.getAmount().compareTo(MAX_SINGLE_LIMIT) > 0) {
return ValidationResult.failure("单笔交易金额超限");
}
// 日累计限额检查
BigDecimal dailyAmount = getDailyAmount(request.getUserId());
if (dailyAmount.add(request.getAmount()).compareTo(MAX_DAILY_LIMIT) > 0) {
return ValidationResult.failure("日累计交易金额超限");
}
return ValidationResult.success();
}
}
🔄 二、支付业务流程深度分析
💳 标准支付流程
支付系统核心业务流程:
用户 商户系统 支付网关 银行/渠道 账务系统 发起支付请求 创建支付订单 风控校验 调用支付渠道 返回支付结果 资金记账 记账完成 返回支付结果 支付结果通知 关键事务点:支付+记账必须原子性 用户 商户系统 支付网关 银行/渠道 账务系统
🏦 支付核心域模型
支付领域模型设计:
java
// 支付订单聚合根
@Entity
@Table(name = "payment_orders")
public class PaymentOrder {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String orderNo; // 支付订单号
private BigDecimal amount; // 支付金额
private Currency currency; // 币种
private PaymentStatus status; // 支付状态
@Embedded
private PayerInfo payer; // 付款方信息
@Embedded
private PayeeInfo payee; // 收款方信息
@OneToMany(cascade = CascadeType.ALL, mappedBy = "paymentOrder")
private List<AccountingEntry> accountingEntries; // 会计分账
// 核心业务逻辑
public void completePayment(PaymentResult result) {
if (this.status != PaymentStatus.PENDING) {
throw new IllegalStateException("支付订单状态异常");
}
this.status = result.isSuccess() ?
PaymentStatus.SUCCESS : PaymentStatus.FAILED;
this.finishedTime = LocalDateTime.now();
// 生成会计分账
generateAccountingEntries();
}
private void generateAccountingEntries() {
// 借贷记账法实现
this.accountingEntries = AccountingRuleEngine
.generateEntries(this);
}
}
// 会计分账实体
@Entity
@Table(name = "accounting_entries")
public class AccountingEntry {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "payment_order_id")
private PaymentOrder paymentOrder;
private String accountNo; // 账户编号
private AccountingDirection direction; // 借贷方向
private BigDecimal amount; // 金额
private LocalDateTime accountingTime; // 记账时间
// 确保借贷平衡
public void validateBalance() {
// 会计平衡校验逻辑
}
}
🏗️ 三、TCC事务模型设计与实现
⚡ TCC模式核心原理
TCC事务三阶段:
TCC事务 Try阶段: 资源预留 Confirm阶段: 确认执行 Cancel阶段: 取消释放
💻 TCC事务实现框架
TCC事务注解定义:
java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TccTransaction {
// 确认方法名
String confirmMethod() default "";
// 取消方法名
String cancelMethod() default "";
// 事务超时时间(秒)
int timeout() default 300;
}
// TCC事务上下文
@Data
public class TccContext {
private String transactionId; // 全局事务ID
private TccStatus status; // 事务状态
private LocalDateTime createTime; // 创建时间
private int retryCount; // 重试次数
// 参与者列表
private List<Participant> participants = new ArrayList<>();
}
// TCC参与者
@Data
public class Participant {
private String serviceName; // 服务名
private String confirmMethod; // 确认方法
private String cancelMethod; // 取消方法
private Object[] parameters; // 方法参数
private Class<?>[] parameterTypes; // 参数类型
}
TCC事务管理器:
java
@Component
public class TccTransactionManager {
@Autowired
private TccTransactionRepository transactionRepository;
@Autowired
private ApplicationContext applicationContext;
/**
* 开启TCC事务
*/
public TccContext beginTransaction() {
TccContext context = new TccContext();
context.setTransactionId(generateTransactionId());
context.setStatus(TccStatus.TRYING);
context.setCreateTime(LocalDateTime.now());
transactionRepository.save(context);
return context;
}
/**
* 注册参与者
*/
public void registerParticipant(TccContext context, Participant participant) {
context.getParticipants().add(participant);
transactionRepository.update(context);
}
/**
* 提交事务(Confirm阶段)
*/
@Transactional
public void commit(TccContext context) {
// 检查事务状态
if (context.getStatus() != TccStatus.TRYING) {
throw new TccException("事务状态异常,无法提交");
}
// 执行所有Confirm操作
for (Participant participant : context.getParticipants()) {
try {
executeConfirm(participant);
} catch (Exception e) {
// 记录失败,继续执行其他Confirm
log.error("Confirm操作执行失败: {}", participant.getServiceName(), e);
// 触发补偿机制
scheduleRetry(context);
throw new TccException("事务提交失败", e);
}
}
// 更新事务状态
context.setStatus(TccStatus.CONFIRMED);
transactionRepository.update(context);
}
/**
* 回滚事务(Cancel阶段)
*/
@Transactional
public void rollback(TccContext context) {
if (context.getStatus() != TccStatus.TRYING) {
return; // 已确认的事务不能回滚
}
// 逆序执行Cancel操作
List<Participant> reversedParticipants =
new ArrayList<>(context.getParticipants());
Collections.reverse(reversedParticipants);
for (Participant participant : reversedParticipants) {
try {
executeCancel(participant);
} catch (Exception e) {
log.error("Cancel操作执行失败: {}", participant.getServiceName(), e);
// 记录异常,继续执行其他Cancel
scheduleCancelRetry(context, participant);
}
}
context.setStatus(TccStatus.CANCELLED);
transactionRepository.update(context);
}
private void executeConfirm(Participant participant) {
Object service = applicationContext.getBean(participant.getServiceName());
Method method = service.getClass().getMethod(
participant.getConfirmMethod(), participant.getParameterTypes());
method.invoke(service, participant.getParameters());
}
private void executeCancel(Participant participant) {
// 类似executeConfirm的实现
}
}
🏦 支付场景TCC实战
资金转账TCC实现:
java
@Service
public class FundTransferService {
@Autowired
private TccTransactionManager transactionManager;
@TccTransaction(
confirmMethod = "confirmTransfer",
cancelMethod = "cancelTransfer"
)
public TransferResult tryTransfer(TransferRequest request) {
TccContext context = transactionManager.beginTransaction();
try {
// 1. 冻结付款方资金
freezePayerAmount(request, context);
// 2. 预占收款方额度
preOccupyPayeeAmount(request, context);
// 3. 记录转账流水
recordTransferFlow(request, context);
transactionManager.commit(context);
return TransferResult.success();
} catch (Exception e) {
transactionManager.rollback(context);
return TransferResult.failure(e.getMessage());
}
}
// Try阶段:冻结资金
private void freezePayerAmount(TransferRequest request, TccContext context) {
Participant participant = new Participant();
participant.setServiceName("accountService");
participant.setConfirmMethod("confirmFreeze");
participant.setCancelMethod("cancelFreeze");
participant.setParameters(new Object[]{request.getPayerAccount(), request.getAmount()});
// 执行资金冻结
boolean success = accountService.freezeAmount(
request.getPayerAccount(), request.getAmount());
if (success) {
transactionManager.registerParticipant(context, participant);
} else {
throw new TransferException("资金冻结失败");
}
}
// Confirm阶段:实际扣款
public void confirmTransfer(TransferRequest request) {
// 实际扣减付款方资金
accountService.deductAmount(request.getPayerAccount(), request.getAmount());
// 实际增加收款方资金
accountService.addAmount(request.getPayeeAccount(), request.getAmount());
// 更新转账状态为成功
transferFlowService.updateStatus(request.getFlowNo(), TransferStatus.SUCCESS);
}
// Cancel阶段:解冻资金
public void cancelTransfer(TransferRequest request) {
// 解冻付款方资金
accountService.unfreezeAmount(request.getPayerAccount(), request.getAmount());
// 释放收款方额度
accountService.releasePreOccupiedAmount(request.getPayeeAccount(), request.getAmount());
// 更新转账状态为失败
transferFlowService.updateStatus(request.getFlowNo(), TransferStatus.FAILED);
}
}
账户服务TCC实现:
java
@Service
public class AccountService {
/**
* Try阶段:资金冻结
*/
public boolean freezeAmount(String accountNo, BigDecimal amount) {
// 使用乐观锁防止并发问题
int affectedRows = accountMapper.freezeAmount(accountNo, amount);
return affectedRows > 0;
}
/**
* Confirm阶段:实际扣款
*/
public void confirmFreeze(String accountNo, BigDecimal amount) {
// 扣减冻结金额,增加已扣款金额
accountMapper.confirmDeduct(accountNo, amount);
// 记录资金变动流水
recordFundFlow(accountNo, amount, FlowType.DEDUCT);
}
/**
* Cancel阶段:解冻资金
*/
public void cancelFreeze(String accountNo, BigDecimal amount) {
// 解冻资金
accountMapper.cancelFreeze(accountNo, amount);
// 记录解冻流水
recordFundFlow(accountNo, amount, FlowType.UNFREEZE);
}
}
// MyBatis Mapper实现
@Mapper
public interface AccountMapper {
@Update("UPDATE accounts SET frozen_amount = frozen_amount + #{amount}, " +
"available_amount = available_amount - #{amount}, " +
"version = version + 1 " +
"WHERE account_no = #{accountNo} AND available_amount >= #{amount} " +
"AND version = #{version}")
int freezeAmount(@Param("accountNo") String accountNo,
@Param("amount") BigDecimal amount,
@Param("version") Long version);
@Update("UPDATE accounts SET frozen_amount = frozen_amount - #{amount}, " +
"actual_amount = actual_amount - #{amount}, " +
"version = version + 1 " +
"WHERE account_no = #{accountNo} AND frozen_amount >= #{amount}")
int confirmDeduct(@Param("accountNo") String accountNo,
@Param("amount") BigDecimal amount);
}
📨 四、消息事务与最终一致性
🔄 基于消息的最终一致性
事务消息架构设计:
业务操作 预发送消息 本地事务 确认发送消息 消息队列 消费者处理 业务从操作
💬 可靠消息最终一致性实现
事务消息表设计:
sql
CREATE TABLE transaction_messages (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
message_id VARCHAR(64) NOT NULL UNIQUE,
topic VARCHAR(100) NOT NULL,
tag VARCHAR(100),
message_body JSON NOT NULL,
business_key VARCHAR(100),
status VARCHAR(20) NOT NULL DEFAULT 'PREPARED',
retry_count INT NOT NULL DEFAULT 0,
next_retry_time DATETIME,
created_time DATETIME NOT NULL,
updated_time DATETIME NOT NULL,
INDEX idx_status_retry (status, next_retry_time),
INDEX idx_business_key (business_key)
);
事务消息服务:
java
@Service
@Transactional
public class TransactionMessageService {
@Autowired
private TransactionMessageMapper messageMapper;
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 预发送消息(在本地事务中)
*/
public void prepareMessage(TransactionMessage message) {
message.setStatus(MessageStatus.PREPARED);
message.setCreatedTime(LocalDateTime.now());
message.setUpdatedTime(LocalDateTime.now());
messageMapper.insert(message);
}
/**
* 确认发送消息(本地事务提交后)
*/
public void confirmAndSend(String messageId) {
TransactionMessage message = messageMapper.selectByMessageId(messageId);
if (message == null) {
throw new MessageException("消息不存在: " + messageId);
}
// 发送消息到MQ
try {
Message<Object> mqMessage = MessageBuilder
.withPayload(message.getMessageBody())
.setHeader("KEYS", message.getMessageId())
.build();
rocketMQTemplate.send(message.getTopic(), mqMessage);
// 更新消息状态为已发送
message.setStatus(MessageStatus.SENT);
message.setUpdatedTime(LocalDateTime.now());
messageMapper.update(message);
} catch (Exception e) {
// 发送失败,记录重试
handleSendFailure(message, e);
}
}
/**
* 消息补偿任务
*/
@Scheduled(fixedDelay = 30000) // 每30秒执行一次
public void compensateMessages() {
List<TransactionMessage> pendingMessages =
messageMapper.selectByStatusAndRetry(
MessageStatus.PREPARED,
LocalDateTime.now()
);
for (TransactionMessage message : pendingMessages) {
if (message.getRetryCount() >= MAX_RETRY_COUNT) {
// 超过最大重试次数,标记为失败
message.setStatus(MessageStatus.FAILED);
messageMapper.update(message);
alertService.sendAlert("消息发送失败: " + message.getMessageId());
continue;
}
try {
confirmAndSend(message.getMessageId());
} catch (Exception e) {
// 更新重试信息
message.setRetryCount(message.getRetryCount() + 1);
message.setNextRetryTime(calculateNextRetryTime(message.getRetryCount()));
messageMapper.update(message);
}
}
}
}
🏦 支付结果通知最终一致性
支付结果通知架构:
java
@Service
public class PaymentNotifyService {
@Autowired
private TransactionMessageService messageService;
/**
* 支付成功处理(事务边界内)
*/
@FinancialTransactional
public void handlePaymentSuccess(PaymentSuccessEvent event) {
// 1. 更新支付订单状态
paymentOrderService.updateStatus(event.getOrderNo(), PaymentStatus.SUCCESS);
// 2. 资金记账
accountingService.recordAccountingEntries(event);
// 3. 预发送通知消息
TransactionMessage message = new TransactionMessage();
message.setMessageId(generateMessageId());
message.setTopic("PAYMENT_SUCCESS_NOTIFY");
message.setBusinessKey(event.getOrderNo());
message.setMessageBody(serializeEvent(event));
messageService.prepareMessage(message);
// 4. 本地事务提交后,消息会被确认发送
}
/**
* 消息监听器处理支付结果通知
*/
@RocketMQMessageListener(
topic = "PAYMENT_SUCCESS_NOTIFY",
consumerGroup = "payment-notify-group"
)
@Service
public class PaymentNotifyListener implements RocketMQListener<PaymentSuccessEvent> {
@Override
public void onMessage(PaymentSuccessEvent event) {
try {
// 通知商户系统
merchantNotifyService.notifyPaymentSuccess(event);
// 记录通知结果
notifyRecordService.recordSuccess(event.getOrderNo());
} catch (Exception e) {
log.error("支付结果通知失败: {}", event.getOrderNo(), e);
// 重试机制
if (needRetry(e)) {
throw new RuntimeException("需要重试", e);
} else {
// 业务异常,记录失败
notifyRecordService.recordFailure(event.getOrderNo(), e.getMessage());
}
}
}
}
}
🔒 五、幂等防重与风控结合
🛡️ 金融级幂等性设计
幂等性设计层次:
请求层防重 业务层幂等 数据层约束 风控层校验
💳 支付幂等性实战
全局幂等控制:
java
@Service
public class GlobalIdempotentService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
/**
* 生成幂等令牌
*/
public String generateIdempotentToken(String businessType, String businessKey) {
String token = UUID.randomUUID().toString();
String redisKey = buildRedisKey(businessType, businessKey);
// 设置令牌,有效期24小时
redisTemplate.opsForValue().set(
redisKey, token, Duration.ofHours(24));
return token;
}
/**
* 校验幂等性
*/
public IdempotentResult checkIdempotent(String businessType,
String businessKey,
String token) {
String redisKey = buildRedisKey(businessType, businessKey);
String storedToken = redisTemplate.opsForValue().get(redisKey);
if (storedToken == null) {
// 首次请求
return IdempotentResult.firstRequest();
}
if (storedToken.equals(token)) {
// 重复请求,返回之前的结果
String result = redisTemplate.opsForValue().get(redisKey + ":result");
return IdempotentResult.duplicateRequest(result);
} else {
// 令牌不匹配,可能被篡改
return IdempotentResult.tokenMismatch();
}
}
/**
* 存储处理结果
*/
public void storeResult(String businessType, String businessKey,
String token, String result) {
String redisKey = buildRedisKey(businessType, businessKey);
// 存储结果,有效期稍长于令牌
redisTemplate.opsForValue().set(
redisKey + ":result", result, Duration.ofHours(25));
}
}
// 幂等性注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
// 业务类型
String businessType();
// 业务键的SPEL表达式
String businessKeySpEL() default "";
// 令牌参数名
String tokenParam() default "idempotentToken";
// 有效期(秒)
long ttl() default 86400;
}
幂等性切面实现:
java
@Aspect
@Component
public class IdempotentAspect {
@Autowired
private GlobalIdempotentService idempotentService;
@Around("@annotation(idempotent)")
public Object aroundAdvice(ProceedingJoinPoint joinPoint, Idempotent idempotent)
throws Throwable {
// 解析业务键
String businessKey = parseBusinessKey(joinPoint, idempotent.businessKeySpEL());
// 获取幂等令牌
String token = getTokenFromParams(joinPoint, idempotent.tokenParam());
// 校验幂等性
IdempotentResult result = idempotentService.checkIdempotent(
idempotent.businessType(), businessKey, token);
if (result.isDuplicate()) {
// 重复请求,直接返回之前的结果
return deserializeResult(result.getResult());
}
if (result.isTokenMismatch()) {
throw new IdempotentException("幂等令牌不匹配");
}
// 首次请求,执行业务逻辑
Object proceedResult = joinPoint.proceed();
// 存储处理结果
idempotentService.storeResult(
idempotent.businessType(), businessKey, token,
serializeResult(proceedResult));
return proceedResult;
}
}
🔐 风控与幂等结合
风控幂等一体化设计:
java
@Service
public class RiskAwareIdempotentService {
/**
* 风控增强的幂等校验
*/
public RiskIdempotentResult checkWithRisk(String businessType,
String businessKey,
String token,
RiskContext riskContext) {
// 1. 基础幂等校验
IdempotentResult idempotentResult = idempotentService
.checkIdempotent(businessType, businessKey, token);
// 2. 风控规则校验
RiskAssessment riskAssessment = riskEngine.assess(riskContext);
// 3. 综合决策
return RiskIdempotentResult.builder()
.idempotentResult(idempotentResult)
.riskAssessment(riskAssessment)
.finalDecision(makeFinalDecision(idempotentResult, riskAssessment))
.build();
}
private RiskDecision makeFinalDecision(IdempotentResult idempotentResult,
RiskAssessment riskAssessment) {
if (idempotentResult.isDuplicate()) {
// 重复请求,根据风控等级决定是否允许
if (riskAssessment.getRiskLevel() == RiskLevel.HIGH) {
return RiskDecision.REJECT; // 高风险重复请求拒绝
}
return RiskDecision.ALLOW; // 低风险允许
}
// 首次请求,根据风控结果决策
switch (riskAssessment.getRiskLevel()) {
case LOW:
return RiskDecision.ALLOW;
case MEDIUM:
return RiskDecision.REVIEW; // 需要人工审核
case HIGH:
return RiskDecision.REJECT;
default:
return RiskDecision.REVIEW;
}
}
}
// 支付服务风控集成
@Service
public class PaymentServiceWithRisk {
@Idempotent(businessType = "payment", businessKeySpEL = "#request.orderNo")
public PaymentResult processPayment(PaymentRequest request) {
// 构建风控上下文
RiskContext riskContext = buildRiskContext(request);
// 风控+幂等综合校验
RiskIdempotentResult riskResult = riskAwareIdempotentService
.checkWithRisk("payment", request.getOrderNo(),
request.getIdempotentToken(), riskContext);
// 根据决策结果处理
switch (riskResult.getFinalDecision()) {
case ALLOW:
return doPayment(request);
case REVIEW:
return submitReview(request);
case REJECT:
throw new PaymentRejectedException("支付请求被风控拒绝");
default:
throw new IllegalStateException("未知决策结果");
}
}
}
🏦 六、支付中心分布式架构实战
🏗️ 支付中心整体架构
支付中心微服务架构:
API网关 支付接入层 商户服务 风控服务 支付核心服务 渠道路由服务 资金记账服务 对账服务 银行渠道A 银行渠道B 第三方支付
🔧 支付核心服务实现
支付订单状态机:
java
@Component
public class PaymentOrderStateMachine {
private final StateMachine<PaymentStatus, PaymentEvent> stateMachine;
/**
* 支付状态转换
*/
public PaymentOrder handleEvent(PaymentOrder order, PaymentEvent event) {
if (!stateMachine.sendEvent(event)) {
throw new PaymentException("状态转换失败: " + order.getStatus() + " -> " + event);
}
order.setStatus(stateMachine.getState().getId());
return order;
}
@Configuration
@EnableStateMachine
public static class PaymentStateMachineConfig
extends StateMachineConfigurerAdapter<PaymentStatus, PaymentEvent> {
@Override
public void configure(StateMachineStateConfigurer<PaymentStatus, PaymentEvent> states)
throws Exception {
states.withStates()
.initial(PaymentStatus.INIT)
.state(PaymentStatus.PENDING)
.state(PaymentStatus.PROCESSING)
.state(PaymentStatus.SUCCESS)
.state(PaymentStatus.FAILED)
.state(PaymentStatus.REFUNDED)
.end(PaymentStatus.SUCCESS)
.end(PaymentStatus.FAILED)
.end(PaymentStatus.REFUNDED);
}
@Override
public void configure(StateMachineTransitionConfigurer<PaymentStatus, PaymentEvent> transitions)
throws Exception {
transitions
.withExternal()
.source(PaymentStatus.INIT).target(PaymentStatus.PENDING)
.event(PaymentEvent.CREATE)
.and()
.withExternal()
.source(PaymentStatus.PENDING).target(PaymentStatus.PROCESSING)
.event(PaymentEvent.PAY)
.and()
.withExternal()
.source(PaymentStatus.PROCESSING).target(PaymentStatus.SUCCESS)
.event(PaymentEvent.SUCCESS)
.and()
.withExternal()
.source(PaymentStatus.PROCESSING).target(PaymentStatus.FAILED)
.event(PaymentEvent.FAIL);
}
}
}
支付路由策略:
java
@Service
public class PaymentChannelRouter {
/**
* 智能渠道路由
*/
public PaymentChannel route(PaymentRequest request, RoutingStrategy strategy) {
List<PaymentChannel> availableChannels = channelService
.getAvailableChannels(request);
switch (strategy) {
case COST_OPTIMAL:
return routeByCost(availableChannels);
case SUCCESS_RATE_OPTIMAL:
return routeBySuccessRate(availableChannels);
case SPEED_OPTIMAL:
return routeBySpeed(availableChannels);
case LOAD_BALANCE:
return routeByLoadBalance(availableChannels);
default:
return routeByDefault(availableChannels);
}
}
/**
* 基于成功率的路由
*/
private PaymentChannel routeBySuccessRate(List<PaymentChannel> channels) {
return channels.stream()
.max(Comparator.comparingDouble(this::calculateSuccessScore))
.orElseThrow(() -> new RoutingException("无可用支付渠道"));
}
private double calculateSuccessScore(PaymentChannel channel) {
// 综合考虑历史成功率、当前状态、成本等因素
double baseSuccessRate = channel.getHistoricalSuccessRate();
double currentHealth = channel.getCurrentHealthScore();
double costFactor = 1.0 - channel.getCostRate() * 0.1; // 成本影响系数
return baseSuccessRate * currentHealth * costFactor;
}
}
📊 资金对账系统
对账核心流程:
java
@Service
@Transactional
public class ReconciliationService {
/**
* 执行对账
*/
public ReconciliationResult reconcile(ReconciliationTask task) {
// 1. 获取渠道对账文件
List<ChannelTransaction> channelTransactions =
channelService.downloadReconciliationFile(task.getChannel(), task.getAccountDate());
// 2. 获取系统交易数据
List<SystemTransaction> systemTransactions =
transactionService.getTransactionsByDate(task.getAccountDate());
// 3. 数据匹配对账
ReconciliationResult result = matchTransactions(
channelTransactions, systemTransactions);
// 4. 差异处理
handleDiscrepancies(result.getDiscrepancies());
// 5. 记录对账结果
recordReconciliationResult(task, result);
return result;
}
/**
* 交易匹配算法
*/
private ReconciliationResult matchTransactions(
List<ChannelTransaction> channelTransactions,
List<SystemTransaction> systemTransactions) {
ReconciliationResult result = new ReconciliationResult();
// 使用交易流水号作为匹配键
Map<String, ChannelTransaction> channelMap = channelTransactions.stream()
.collect(Collectors.toMap(ChannelTransaction::getTransactionNo, Function.identity()));
Map<String, SystemTransaction> systemMap = systemTransactions.stream()
.collect(Collectors.toMap(SystemTransaction::getTransactionNo, Function.identity()));
// 找出匹配的交易
for (String transactionNo : channelMap.keySet()) {
if (systemMap.containsKey(transactionNo)) {
ChannelTransaction channelTx = channelMap.get(transactionNo);
SystemTransaction systemTx = systemMap.get(transactionNo);
if (isTransactionMatch(channelTx, systemTx)) {
result.addMatchedTransaction(new MatchedTransaction(channelTx, systemTx));
} else {
result.addDiscrepancy(new TransactionDiscrepancy(channelTx, systemTx));
}
} else {
// 渠道有系统无
result.addDiscrepancy(new TransactionDiscrepancy(
channelMap.get(transactionNo), null));
}
}
// 系统有渠道无
for (String transactionNo : systemMap.keySet()) {
if (!channelMap.containsKey(transactionNo)) {
result.addDiscrepancy(new TransactionDiscrepancy(
null, systemMap.get(transactionNo)));
}
}
return result;
}
}
🔍 监控与运维体系
支付监控看板:
java
@Configuration
@EnableConfigurationProperties(PaymentMonitorProperties.class)
public class PaymentMonitorConfig {
@Bean
@ExportMetric
public MeterRegistryCustomizer<MeterRegistry> paymentMetrics() {
return registry -> registry.config().commonTags(
"application", "payment-center",
"environment", "production"
);
}
@Bean
public TimedAspect timedAspect(MeterRegistry registry) {
return new TimedAspect(registry);
}
@Bean
public CountedAspect countedAspect(MeterRegistry registry) {
return new CountedAspect(registry);
}
}
// 支付监控服务
@Service
public class PaymentMonitorService {
private final MeterRegistry meterRegistry;
private final Counter paymentSuccessCounter;
private final Counter paymentFailureCounter;
private final Timer paymentProcessTimer;
public PaymentMonitorService(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.paymentSuccessCounter = Counter.builder("payment.result")
.tag("status", "success")
.register(meterRegistry);
this.paymentFailureCounter = Counter.builder("payment.result")
.tag("status", "failure")
.register(meterRegistry);
this.paymentProcessTimer = Timer.builder("payment.process.time")
.register(meterRegistry);
}
@Timed(value = "payment.process", description = "支付处理时间")
public PaymentResult monitorPaymentProcess(Supplier<PaymentResult> paymentProcess) {
return paymentProcessTimer.record(() -> {
try {
PaymentResult result = paymentProcess.get();
if (result.isSuccess()) {
paymentSuccessCounter.increment();
} else {
paymentFailureCounter.increment();
}
return result;
} catch (Exception e) {
paymentFailureCounter.increment();
throw e;
}
});
}
}