背景:一次通道接入的稳定性担忧

去年底我帮一个做电商的商户老周排查支付掉单。他的聚合支付平台日均交易笔数从几百涨到几千,接入的一条新银行通道频繁返回“交易超时”。

老周的平台之前主要走线上扫码,为了降成本切了部分流量到这条新通道。结果上线第二周就出现不规律失败,商户群质问消息刷屏,他压力很大。

按行业通行做法,新通道上线前必须做两件事:规格对标稳定性压测。但老周只核对了接口规范,跳过了压测这一步。

起因:为什么必须做通道稳定性测试

起因很简单——通道提供商的技术文档明确写了并发支撑能力,但老周从未验证过真实条件下的表现。

那条通道标称支持“200笔每秒,平均响应2000ms”。老周估算自己在高峰也就每秒十几笔,觉得完全够用,没多想。可他忽略了一个细节:标称值是对方核心系统处理能力,不代表端到端链路能力

我带他复盘时发现,失败并不是因为通道处理不了,而是卡在了网络边缘。聚合支付平台哪个好?从费率和通道稳定性对比这篇文章里也提过,没经过压测的通道,再便宜也不能直接切量。老周需要的是把测试方法标准化。

经过:压测中暴露的超时漩涡

我们直接在生产前半小时的窗口期内铺了台压测节点。脚本用Python的locust,模拟在线支付通知回调的HTTP POST,并发用户数从50逐步加到300。

第一个异常出现在并发数160左右:Error率从0直接跳到12%,响应时间P99飙到8300ms。通道方返回的都是“交易超时”或连接重置。老周立刻加了重试机制,但重试让积压更严重。

我把压测机抓到旁路看TCP连接状态,发现大量SYN_SENT后无回应,说明请求根本没到达通道服务器。检查本机防火墙日志,发现每分钟有超过两万条“连接状态表满”的丢弃记录

这就是冷门细节了——很多人压测只看应用层,不关心内核连接追踪表。当时机器的net.netfilter.nf_conntrack_max只有65536,压测一上来立刻打满,新连接被直接丢弃。通道侧完全不知情,质量监控也显示正常。

转折:一个内核参数改变了局面

真正改变局面的操作是调整连接追踪相关的几个内核参数,net.netfilter.nf_conntrack_tcp_timeout_established从默认的432000秒改到600秒,再把net.netfilter.nf_conntrack_max提高到262144。

同时我们给支付客户端设置了连接超时3000ms读取超时5000ms,避免半开连接占用追踪表空间。重试机制也做了退避算法:首次失败等200ms,第二次等400ms,最多尝试3次。这部分逻辑我在易支付订单状态异常复盘:延时通知引发的重复发货中提过类似思路,幂等设计必须结合超时策略一起调。

重新压测,并发200、300均未出现异常。P99响应时间稳定在2200ms左右,与通道标称值基本吻合。那晚我们蹲到真实交易高峰,通道侧零故障,商户群安静了。

结果:调整后的可靠表现与真实数据

最终这条通道平稳运行了三个月,期间日交易量从不足千笔涨到最高单日超过三万笔,没有出现过一次因网络内核瓶颈导致的超时。

老周那边月流水从几万涨到十几万,通道手续费成本反而下降了约三分之一。这带来的直接好处是业务可以放心放量,而不是每天盯着告警过日子。

我们事后把整套稳定性测试方法固化成三个检查点:

  • 压测时监控内核nf_conntrack_count是否触发上限
  • 设定应用层超时必须小于内核超时,形成双层防护
  • 重试策略必须结合通道扩展能力,避免雪崩
任何新通道上线前,都会先跑一轮不低于500并发的冒烟压测,这套方法至今没再出过问题。

如果重来:我会这样建议通道稳定性测试

如果回到当时,我会让老周在上线前三天就做一套完整的端到端压测方案,而不是等出了问题再应急。

首先,压测工具要捕捉到低于应用层的信号。执行命令检查:sysctl net.netfilter.nf_conntrack_maxconntrack -S 是每次测试的固定动作,不能等到线上丢包才看。

其次,通道标称值只能作为参考上限的七成来用。如果通道方声称200 TPS,实际方案设计按140 TPS走,留出缓冲空间。分布式架构下,瓶颈可能不在对方核心,而在中间的云负载均衡或你的出网带宽。

最后,测试结果本身要形成文档并同步到所有相关方。交易失败率高于0.1%并持续两分钟,自动触发降级切回原通道,这套规则需要写入运维脚本。没有自动熔断的压测,只能算半成品。