Arch Day 46: 收单系统设计 — 聚合支付网关的完整架构
收单系统是支付链路的入口和大脑——它面向商户统一收款接口,在内部完成路由决策、风控拦截、通道调度、限额控制、异步通知等全流程,是支付平台中逻辑最密集、对外耦合最多的子系统。
日期: 2026-05-15 (Day 46) 阶段: 第二阶段 - 金融域深度 标签: #收单系统 #支付网关 #通道路由 #商户管理 #幂等设计 #熔断降级
核心概念
一句话定义
收单系统是支付链路的入口和大脑——它面向商户统一收款接口,在内部完成路由决策、风控拦截、通道调度、限额控制、异步通知等全流程,是支付平台中逻辑最密集、对外耦合最多的子系统。
为什么资深架构师仍需关注
| 维度 | 关注理由 |
|---|---|
| 入口复杂度 | 同时对接几十个外部通道,每个通道接口不同、规则不同、稳定性不同 |
| 路由策略 | 通道选择直接影响成本、成功率、用户体验——是技术和业务的交汇点 |
| 幂等设计 | 收单是重复请求的高发区(网络超时重试),幂等设计是核心中的核心 |
| 弹性工程 | 通道故障是常态而非异常,如何自动降级和切换决定了系统的鲁棒性 |
| 商户生态 | 商户管理涉及进件、审核、签约、费率、结算——是一个完整的B2B平台 |
常见误区与反模式
| 误区 | 真相 |
|---|---|
| "聚合支付就是一个HTTP转发代理" | 聚合支付网关是有状态的、有决策能力的业务系统,不是简单代理 |
| "通道越多越好" | 通道管理有运维成本,每增加一个通道就增加一层复杂性和对账成本 |
| "路由策略用固定规则就行" | 通道状态实时变化,静态路由无法应对通道故障、限额耗尽等动态场景 |
| "成功率只看通道返回结果" | 真实成功率要考虑:网络超时、通道降级、限额拦截、风控拦截等全链路 |
| "商户进件是一次性工作" | 商户全生命周期管理:进件→审核→签约→变更→续约→冻结→关闭 |
知识点详解
知识点1:聚合支付网关整体架构
┌─────────────────────────────────────────────────────────────┐
│ 聚合支付网关架构全景 │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 接入层 (Access Layer) │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │统一API │ │SDK集成 │ │H5收银台 │ │ │
│ │ │(REST) │ │(Android/ │ │(Web端) │ │ │
│ │ │ │ │ iOS) │ │ │ │ │
│ │ └─────┬────┘ └─────┬────┘ └─────┬────┘ │ │
│ └────────┼──────────────┼──────────────┼──────────────┘ │
│ └──────────────┼──────────────┘ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 业务处理层 (Business Layer) │ │
│ │ │ │
│ │ ① 参数校验 → ② 幂等检查 → ③ 商户验证 → ④ 风控拦截 │ │
│ │ ↓ │ │
│ │ ⑤ 限额检查 → ⑥ 路由决策 → ⑦ 组装报文 → ⑧ 通道调用 │ │
│ │ ↓ │ │
│ │ ⑨ 结果处理 → ⑩ 状态更新 → ⑪ 异步通知 → ⑫ 日志记录 │ │
│ └─────────────────────────────────────────────────────┘ │
│ ↕ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 通道适配层 (Channel Adapter Layer) │ │
│ │ │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │银联 │ │微信 │ │支付宝 │ │银行直连 │ │ │
│ │ │Adapter │ │Adapter │ │Adapter │ │Adapter │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │Apple │ │Google │ │PayPal │ ... │ │
│ │ │Pay │ │Pay │ │Adapter │ │ │
│ │ └────────┘ └────────┘ └────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 支撑服务层 (Supporting Services) │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │商户管理 │ │通道管理 │ │路由引擎 │ │风控引擎 │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ │ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ │
│ │ │限额控制 │ │密钥管理 │ │对账服务 │ │通知服务 │ │ │
│ │ └────────┘ └────────┘ └────────┘ └────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
知识点2:收单交易完整流程(12步)
商户/用户 支付网关 外部通道
│ │ │
│ ① 支付请求 │ │
│ (orderId, amount, │ │
│ payMethod, ...) │ │
│ ─────────────────────→ │ │
│ │ │
│ ② 参数校验 │
│ (签名验证、必填校验、格式校验) │
│ │ │
│ ③ 幂等检查 │
│ (idempotencyKey查Redis) │
│ │ │
│ ④ 商户验证 │
│ (商户状态、权限、费率) │
│ │ │
│ ⑤ 风控拦截 │
│ (规则引擎+ML模型) │
│ │ │
│ ⑥ 限额检查 │
│ (单笔/日累/月累) │
│ │ │
│ ⑦ 路由决策 │
│ (选择最优通道) │
│ │ │
│ ⑧ 报文组装 │
│ (统一→通道特定格式) │
│ │ │
│ │ ⑨ 调用通道 │
│ │ ─────────────────────→ │
│ │ │
│ │ ⑩ 通道响应 │
│ │ ◄───────────────────── │
│ │ │
│ ⑪ 结果处理 │
│ (状态映射、入库、更新缓存) │
│ │ │
│ ⑫ 返回结果 │ │
│ ◄───────────────────── │ │
│ │ │
│ (异步) 通知商户回调 │
│ ◄ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ │
知识点3:通道路由策略设计
通道路由是收单系统的大脑,决定每笔交易走哪个通道。好的路由策略直接影响成本和成功率。
五种路由策略
路由策略决策树
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 成本最优路由 (Cost-Optimal)
├── 目标:最小化通道手续费
├── 算法:按费率排序,选最低
├── 适用:交易量大、费率敏感的商户
└── 风险:便宜的通道可能成功率低
2. 成功率最优路由 (Success-Rate-Optimal)
├── 目标:最大化交易成功率
├── 算法:基于历史成功率加权选择
├── 适用:高客单价交易(如机票、奢侈品)
└── 实现:滑动窗口统计各通道成功率
3. 限额均衡路由 (Quota-Balanced)
├── 目标:均匀分配各通道额度
├── 算法:根据剩余额度比例分配
├── 适用:多通道签约,各通道有日限额
└── 实现:实时追踪各通道已用额度
4. 权重路由 (Weighted)
├── 目标:综合考虑多因素
├── 算法:成功率×W1 + 费率×W2 + 速度×W3
├── 适用:通用场景
└── 实现:可动态调整权重
5. 灰度路由 (Canary)
├── 目标:新通道上线验证
├── 算法:小流量(5%→10%→30%→100%)逐步放量
├── 适用:新接入通道的稳定性验证
└── 实现:基于流量百分比的分流
路由引擎架构
// 路由引擎核心接口设计
interface RouteRequest {
merchantId: string;
payMethod: 'WECHAT_SCAN' | 'ALIPAY_SCAN' | 'BANK_CARD' | 'QUICK_PAY';
amount: number; // 分
currency: string;
bankCode?: string; // 银行编码(快捷支付需要)
cardType?: 'DEBIT' | 'CREDIT';
}
interface RouteResult {
channelCode: string; // 选中的通道编码
channelName: string;
feeRate: number; // 通道费率
estimatedFee: number; // 预估手续费
routeReason: string; // 路由原因(用于审计)
fallbackChannels: string[]; // 备选通道列表
}
interface RouteEngine {
// 核心路由方法
route(request: RouteRequest): RouteResult;
// 路由策略链
strategies: RouteStrategy[];
// 通道过滤器(先排除不可用的)
filters: ChannelFilter[];
}
// 路由执行流程
// Step 1: 候选通道集合 = 所有通道
// Step 2: 过滤器链
// ├── 状态过滤:排除已关闭/维护中的通道
// ├── 支付方式过滤:排除不支持该支付方式的通道
// ├── 限额过滤:排除已超限额的通道
// ├── 商户过滤:排除商户未签约的通道
// └── 银行过滤:排除不支持该银行的通道(快捷支付)
// Step 3: 路由策略选择最优通道
// Step 4: 记录路由决策(用于分析和审计)
路由决策的权重计算示例
| 通道 | 成功率(W=0.4) | 费率(W=0.3) | 速度(W=0.2) | 稳定性(W=0.1) | 综合得分 |
|---|---|---|---|---|---|
| 通道A | 99.2% (0.992) | 0.3% (0.997) | 200ms (0.95) | 99.9% (0.999) | 0.979 |
| 通道B | 97.5% (0.975) | 0.2% (0.998) | 150ms (0.97) | 99.5% (0.995) | 0.979 |
| 通道C | 98.8% (0.988) | 0.5% (0.995) | 300ms (0.90) | 99.8% (0.998) | 0.973 |
知识点4:商户管理系统
商户全生命周期
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ 进件 │ → │ 审核 │ → │ 签约 │ → │ 正常 │
│ Apply │ │ Review │ │ Sign │ │ Active │
└───────┘ └───┬───┘ └───────┘ └───┬───┘
│ │
┌───▼───┐ ┌─────▼─────┐
│ 拒绝 │ │ 变更/续约 │
│Reject │ │ Change │
└───────┘ └─────┬─────┘
│
┌────▼────┐
│ 冻结/关闭 │
│Freeze/ │
│Close │
└─────────┘
进件信息:
├── 基本信息:商户名称、联系人、地址
├── 资质信息:营业执照、法人身份证、银行开户许可
├── 业务信息:经营范围、预估交易量、行业类别(MCC)
├── 技术信息:回调地址、IP白名单、加密方式
└── 结算信息:结算账户、结算周期、费率方案
审核维度:
├── 资质审核:证照真伪、经营范围合规
├── 风险审核:行业风险等级、反洗钱名单
├── 费率审核:费率方案是否合理
└── 技术审核:接口对接是否规范
商户费率模型:
├── 按比例收费:交易金额 × 费率(如 0.6%)
├── 固定费用:每笔交易固定收费(如 1元/笔)
├── 阶梯费率:按交易量区间差异化(量大费率低)
└── 组合费率:固定费 + 比例费(如 1元 + 0.3%)
知识点5:限额控制体系
限额控制多层级设计
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
层级1:通道限额
├── 单笔限额:通道方规定的单笔最大金额
├── 日累计限额:通道的日总额度
├── 月累计限额:通道的月总额度
└── TPS限额:通道的并发处理能力
层级2:商户限额
├── 单笔限额:根据商户风险等级设定
├── 日累计限额:防止集中大额异常
├── 月累计限额:预算控制
└── 单用户限额:同一用户在同一商户的限制
层级3:用户限额
├── 单笔限额:个人支付上限
├── 日累计限额:每日消费总额
└── 年累计限额:反洗钱相关
层级4:风控限额
├── 动态限额:根据风险评分实时调整
├── 临时限额:特殊活动期间临时提高/降低
└── 应急限额:风险事件时紧急下调
限额检查的Redis实现方案
// 限额控制核心逻辑
interface QuotaChecker {
/**
* 检查并扣减限额
* 使用Redis Lua脚本保证原子性
*/
checkAndDeduct(params: {
channelCode: string;
merchantId: string;
userId: string;
amount: number;
// 返回所有层级的检查结果
}): QuotaCheckResult;
}
// Redis Lua脚本实现原子化限额检查
// KEY[1] = channel:daily:{channelCode}:{date}
// KEY[2] = merchant:daily:{merchantId}:{date}
// ARGV[1] = amount
// ARGV[2] = channelDailyLimit
// ARGV[3] = merchantDailyLimit
const QUOTA_CHECK_LUA = `
local channelUsed = tonumber(redis.call('GET', KEYS[1]) or '0')
local merchantUsed = tonumber(redis.call('GET', KEYS[2]) or '0')
local amount = tonumber(ARGV[1])
local channelLimit = tonumber(ARGV[2])
local merchantLimit = tonumber(ARGV[3])
if channelUsed + amount > channelLimit then
return {0, 'CHANNEL_QUOTA_EXCEEDED', channelUsed, channelLimit}
end
if merchantUsed + amount > merchantLimit then
return {0, 'MERCHANT_QUOTA_EXCEEDED', merchantUsed, merchantLimit}
end
redis.call('INCRBY', KEYS[1], amount)
redis.call('INCRBY', KEYS[2], amount)
redis.call('EXPIRE', KEYS[1], 86400)
redis.call('EXPIRE', KEYS[2], 86400)
return {1, 'OK', channelUsed + amount, merchantUsed + amount}
`;
知识点6:通道管理与熔断降级
通道状态机
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
┌────────┐ 手动/自动开启 ┌──────────┐
│ 正常 │ ◄────────────── │ 维护中 │
│ ACTIVE │ ─────────────→ │ MAINTAIN │
└───┬────┘ 手动关闭 └──────────┘
│
│ 错误率超过阈值
▼
┌────────┐ 冷却期后探活 ┌──────────┐
│ 熔断 │ ─────────────→ │ 半开 │
│ OPEN │ │ HALF_OPEN│
└────────┘ └─────┬────┘
▲ │
│ 探活失败 │ 探活成功
└──────────────────────────┘ │
▼
┌────────┐
│ 恢复 │
│ ACTIVE │
└────────┘
熔断参数设计:
├── 统计窗口:最近60秒
├── 失败率阈值:失败率 > 50%
├── 最小请求数:窗口内至少20笔才触发
├── 熔断时长:30秒(逐步增加:30s→60s→120s)
├── 半开放量:熔断后先放5%流量探活
└── 恢复条件:探活成功率 > 90%
自动切换策略:
├── 主备切换:通道A熔断 → 自动切换到通道B
├── 流量转移:渐进式从故障通道转移到备用通道
├── 人工兜底:所有自动通道都不可用时→告警+人工处理
└── 恢复回切:故障通道恢复后→逐步回切流量
知识点7:收单系统的幂等和防重设计
幂等设计三层保障
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Layer 1: 请求层防重(毫秒级)
┌───────────────────────────────────────┐
│ Redis SETNX(idempotency_key, status) │
│ TTL = 24小时 │
│ │
│ 存在 → 返回缓存结果(如已完成) │
│ → 返回"处理中"(如正在处理) │
│ 不存在 → 设置并继续处理 │
└───────────────────────────────────────┘
Layer 2: 数据库层防重(强一致)
┌───────────────────────────────────────┐
│ 支付订单表: │
│ UNIQUE INDEX (merchant_id, out_order_no)│
│ │
│ INSERT时如果冲突 → 查询已有记录返回 │
│ 保证即使Redis故障也不会重复创建订单 │
└───────────────────────────────────────┘
Layer 3: 通道层防重(透传幂等键)
┌───────────────────────────────────────┐
│ 向通道发送请求时携带唯一交易号 │
│ 通道侧也有自己的防重机制 │
│ 即使我方重复发送,通道也只处理一次 │
└───────────────────────────────────────┘
幂等键(Idempotency Key)设计:
├── 生成方: 由商户生成(保证商户控制唯一性)
├── 格式: merchantId + outOrderNo(商户订单号)
├── 存储: Redis(快速检查) + MySQL(持久化)
├── 过期: 24小时后过期(可配置)
└── 并发: 用Redis的原子操作处理并发场景
对比分析
主流通道类型对比
| 维度 | 银联通道 | 微信支付 | 支付宝 | 银行直连 |
|---|---|---|---|---|
| 接入方式 | SDK/API | API | API | 专线/API |
| 结算周期 | T+1 | T+1(默认) | T+1(默认) | T+0/T+1 |
| 费率范围 | 0.3-0.6% | 0.2-0.6% | 0.2-0.6% | 0.1-0.3% |
| 支付方式 | 刷卡/扫码/快捷 | 扫码/JSAPI/小程序 | 扫码/生活号/小程序 | 快捷/网银 |
| 对账文件 | 批量(T+1) | 批量(T+1) | 批量(T+1) | 批量/实时 |
| 稳定性 | 高 | 高 | 高 | 因行而异 |
| 接入成本 | 中 | 低 | 低 | 高(每家银行单独接) |
路由策略适用场景对比
| 策略 | 适用场景 | 优势 | 劣势 | 实现复杂度 |
|---|---|---|---|---|
| 成本最优 | 价格敏感型商户 | 降低手续费 | 可能牺牲成功率 | 低 |
| 成功率最优 | 高客单价场景 | 最高转化率 | 费用可能偏高 | 中 |
| 限额均衡 | 多通道均衡使用 | 避免单通道超限 | 逻辑较复杂 | 中 |
| 权重综合 | 通用场景 | 灵活可调 | 权重调优需要经验 | 高 |
| 灰度路由 | 新通道上线 | 风险可控 | 新通道验证周期长 | 中 |
架构设计实操
设计目标
设计一个聚合支付网关的完整架构,包含路由引擎、通道管理、商户系统三大核心模块。
核心领域模型
聚合支付网关 DDD 领域模型
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Aggregate: PaymentOrder (支付订单 - 核心聚合根)
├── paymentId: string // 平台支付单号
├── merchantId: string // 商户号
├── outOrderNo: string // 商户订单号
├── amount: Money // 支付金额
├── payMethod: PayMethod // 支付方式
├── status: OrderStatus // 订单状态
├── channelCode: string // 路由通道
├── channelOrderNo: string // 通道订单号
├── routeRecord: RouteRecord // 路由决策记录
├── riskResult: RiskResult // 风控结果
├── createdAt: DateTime
├── updatedAt: DateTime
└── events: DomainEvent[]
OrderStatus 状态机:
CREATED → PROCESSING → SUCCESS
→ FAILED
→ CLOSED (超时关闭)
SUCCESS → REFUNDING → REFUNDED
Aggregate: Merchant (商户)
├── merchantId: string
├── merchantName: string
├── status: MerchantStatus
├── contractInfo: ContractInfo // 签约信息
├── feeConfig: FeeConfig[] // 费率配置
├── settleConfig: SettleConfig // 结算配置
├── riskLevel: RiskLevel // 风险等级
└── channels: MerchantChannel[] // 开通的通道
Aggregate: Channel (支付通道)
├── channelCode: string
├── channelName: string
├── status: ChannelStatus // ACTIVE/MAINTAIN/CIRCUIT_OPEN
├── supportedMethods: PayMethod[]
├── feeRate: FeeRate
├── quotaConfig: QuotaConfig // 限额配置
├── circuitBreaker: CircuitBreakerState
└── healthMetrics: HealthMetrics // 健康指标
支付订单状态机详细设计
┌──────────┐
│ CREATED │ ← 订单创建成功
└────┬─────┘
│ 发起通道调用
▼
┌──────────┐
┌───── │PROCESSING│ ─────┐
│ └──────────┘ │
│ │
通道返回成功 通道返回失败
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ SUCCESS │ │ FAILED │
└────┬─────┘ └──────────┘
│
发起退款请求 超时未响应
▼ │
┌──────────┐ ┌──────▼───┐
│REFUNDING │ │ CLOSED │ ← 超时自动关单
└────┬─────┘ └──────────┘
│
退款成功
▼
┌──────────┐
│ REFUNDED │
└──────────┘
关键规则:
├── CREATED → PROCESSING: 只能发生一次(幂等键保证)
├── PROCESSING → SUCCESS/FAILED: 以通道最终结果为准
├── PROCESSING超时: 启动查询确认→根据结果流转
├── SUCCESS → REFUNDING: 需校验退款金额≤原交易金额
└── 任何终态: 不允许再变更(只能新建)
ADR-046:通道路由采用策略模式+动态权重
| 项目 | 内容 |
|---|---|
| 决策 | 路由引擎采用策略模式(Strategy Pattern),支持运行时动态切换路由策略和调整权重 |
| 状态 | 已采纳 |
| 上下文 | 不同商户、不同场景需要不同的路由策略;通道状态实时变化需要动态响应 |
| 方案A | 硬编码路由规则(if-else) |
| 方案B | 配置化规则引擎(Drools) |
| 方案C | 策略模式 + 过滤器链 + 动态权重 ✓ |
| 决策理由 | 策略模式支持灵活扩展新策略;过滤器链解耦候选通道筛选逻辑;动态权重支持运行时调整,不需要重启 |
| 权衡 | 策略组合的调试复杂度增加,需要完善的路由日志来辅助排查 |
AI增强实践
AI在收单系统中的应用
AI增强的收单系统
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. 智能路由优化
├── 基于ML的成功率预测模型
│ └── 特征:交易金额、时段、商户类型、用户画像、通道历史表现
├── 强化学习(RL)动态调整路由权重
│ └── 奖励函数:成功率×(1-费率)×(1-延迟归一化)
└── A/B测试自动化:新策略小流量验证
2. 商户风险智能评估
├── 进件自动审核:OCR识别证照 + NLP分析经营描述
├── 交易行为异常检测:发现商户侧的异常交易模式
└── 动态风险评级:根据历史交易数据持续更新商户风险等级
3. 通道健康预测
├── 时序预测:预测通道未来1小时的可用性
├── 异常检测:提前发现通道性能退化
└── 容量预测:预测通道限额消耗速度
4. AI辅助运维
├── 告警收敛:相关告警自动聚合
├── 根因分析:故障自动定位
└── 自动止血:发现问题自动切换通道
Prompt示例:路由策略优化
Prompt: 我有以下3个支付通道的历史数据(最近30天):
通道A:成功率98.5%,费率0.35%,平均延迟180ms,日限额500万
通道B:成功率96.2%,费率0.20%,平均延迟120ms,日限额300万
通道C:成功率99.1%,费率0.50%,平均延迟250ms,日限额800万
场景:电商平台,日均交易800万,单笔平均200元。
请帮我:
1. 设计一个综合权重路由策略,给出权重推荐
2. 计算最优的流量分配比例
3. 考虑限额约束后的调整方案
4. 评估预期的整体成功率和手续费成本
与Web3/DeFi的关联
收单系统 vs DEX聚合器
| 维度 | 传统收单系统 | DEX聚合器(1inch/Paraswap) |
|---|---|---|
| 通道概念 | 银联/微信/支付宝等支付通道 | Uniswap/SushiSwap/Curve等DEX |
| 路由逻辑 | 成功率/费率/限额多因素 | 价格最优+滑点最小 |
| 资金流 | 信息流和资金流分离(T+1结算) | 原子交换(一笔链上交易完成) |
| 失败处理 | 重试/切换通道/退款 | 交易revert(天然原子性) |
| 幂等性 | 需要自己实现 | 链上nonce天然幂等 |
| 通道监控 | 成功率/延迟/限额 | 流动性深度/Gas价格/MEV |
启示
- DEX聚合器是"去中心化的收单系统",路由逻辑惊人地相似
- 智能合约的原子性天然解决了传统收单的"掉单"问题
- 但智能合约无法处理"退款",需要在应用层设计dispute resolution
今日思考
深度问题1:通道路由策略应该由业务人员还是系统自动决定?
最佳实践是分层决定:战略级策略(如"新通道灰度上线")由业务人员通过管理后台配置;战术级决策(如"当前这一笔走哪个通道")由系统根据实时数据自动决定;紧急决策(如"通道故障自动切换")由系统自动执行但必须告警通知。把人的判断力和机器的响应速度结合起来。
深度问题2:如何衡量收单系统的"好坏"?
核心指标有四个:支付成功率(用户视角)、通道成本率(财务视角)、端到端延迟(体验视角)、掉单率(技术视角)。其中支付成功率最关键——每提升1个百分点,对商户来说可能意味着数百万的额外收入。
深度问题3:收单系统最容易出问题的环节是什么?
三个高危区:(1)通道异步回调的处理——回调可能延迟、重复、乱序、丢失;(2)超时场景的状态一致性——"我调了通道但不知道结果"是最棘手的状态;(3)对账差异的处理——通道对账文件和自己的交易记录不一致时,如何确定"谁是对的"。
面试题准备
题目1:通道路由策略如何设计?
30秒回答
通道路由采用过滤器链+策略模式:先通过一系列过滤器(状态/支付方式/限额/商户权限)筛选出可用通道集合,再用路由策略(成本最优/成功率最优/权重综合)从候选集中选择最优通道。路由策略支持动态配置和运行时切换。
2分钟回答
路由设计分三步:
第一步,候选通道筛选(排除法)。通过过滤器链依次排除:状态异常的通道(维护中/已熔断)、不支持当前支付方式的通道、已超限额的通道、商户未签约的通道。这一步把"不能用"的全排除。
第二步,策略选择(打分法)。对候选通道进行综合打分。在实际项目中,我用权重模型:成功率(40%) + 费率(30%) + 响应速度(20%) + 稳定性(10%)。权重可以按商户和场景差异化配置。
第三步,故障兜底(fallback)。路由结果包含主选通道和fallback列表。如果主选通道调用失败,自动按fallback顺序切换。
关键的工程细节:路由决策必须记录完整日志(包括候选集、各通道评分、最终选择原因),用于事后分析和优化。成功率数据使用滑动窗口(如最近1小时)实时计算,而非历史全量数据。
追问准备
- 追问1:如何处理新通道没有历史数据的冷启动?→ 灰度路由,先给5%流量,用Thompson Sampling(汤普森采样)或UCB算法平衡探索和利用
- 追问2:路由决策会不会成为性能瓶颈?→ 路由逻辑纯内存计算,通道状态缓存在本地+Redis,单次路由<1ms
题目2:如何处理通道故障的自动切换?
30秒回答
采用熔断器模式(Circuit Breaker):实时监控通道错误率,超过阈值(如50%)自动熔断,流量切换到备用通道。熔断后定期小流量探活,恢复后逐步回切流量。整个过程自动化,但关键状态变更必须告警通知运维。
2分钟回答
通道故障切换分为三个层面:
检测层:实时统计每个通道在滑动窗口内的成功率和延迟。采用滑动窗口而非固定窗口,避免窗口边界的统计毛刺。阈值设计:错误率>50%(且窗口内请求数≥20笔)触发熔断。
决策层:熔断触发后,该通道状态变为OPEN(不再接收新请求),已有的在途交易继续等待结果。同时通知路由引擎从候选集中移除该通道,后续请求自动路由到其他通道。
恢复层:熔断30秒后进入HALF_OPEN状态,放5%的流量进去探活。如果探活成功率>90%,逐步增加流量(5%→20%→50%→100%),全量恢复后进入ACTIVE状态。如果探活失败,重新进入OPEN状态,且等待时间翻倍(30s→60s→120s→最大300s)。
学习资源
| 资源 | 类型 | 推荐理由 |
|---|---|---|
| Stripe API文档 | 文档 | 收单API设计的教科书 |
| 《聚合支付:理论与实务》 | 书籍 | 国内聚合支付的完整介绍 |
| Martin Fowler: Circuit Breaker | 文章 | 熔断器模式的经典阐述 |
| Netflix Hystrix Wiki | 文档 | 熔断器的工业级实现参考 |
| 微信支付官方技术文档 | 文档 | 通道接入的一手资料 |
明日预告
Day 47: 清结算系统设计 — 从收单拿到交易结果后,如何完成清算和结算?核心话题:清算vs结算的本质区别、轧差(Netting)机制、T+N结算周期设计、资金池管理、分账系统设计。这是支付链路中"看不见但最关键"的环节。