1. 事故背景:并发环境下的诡异幂等失效
那天下午三点零二分,我正悠闲地喝着咖啡准备摸鱼,突然钉钉群里客服@全员的消息炸开了锅:"用户投诉重复扣库存!系统又抽风了?"监控大屏上,幂等命中率的曲线从平稳的99.9%直线下坠到97%,日志系统里不断冒出两种看似不相关的错误:
- 数据库唯一键冲突异常(Duplicate entry for key 'uk_idem')
- 支付回调验签失败(NumberFormatException parsing timestamp)
更诡异的是,这些错误都是偶发性的——同一批请求中可能只有1-2条会失败。作为负责库存系统的开发,我立刻意识到问题的严重性:在电商大促期间,这种偶发的幂等失效可能导致超卖或重复扣款,必须立即定位。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 问题现象与初步分析
2.1 错误日志特征分析
从日志系统中提取到的典型错误有两种表现形式:
第一种是数据库唯一键冲突:
java复制2026-03-10 15:02:31 ERROR c.xxx.stock.StockService - duplicate key uk_idem (idem_key=STOCK:9527:2026-03-10 15:02:31)
com.mysql.cj.jdbc.exceptions.MysqlIntegrityConstraintViolationException: Duplicate entry 'STOCK:9527:2026-03-10 15:02:31' for key 'uk_idem'
第二种是时间解析异常:
java复制2026-03-10 15:02:32 ERROR c.xxx.pay.SignService - verify failed, ts=2026-03-10 15:02:32
java.lang.NumberFormatException: For input string: "10 15:0"
at java.lang.Integer.parseInt(Integer.java:...)
at java.text.DigitList.getLong(DigitList.java:...)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:...)
2.2 幂等机制设计回顾
我们的库存扣减服务采用了经典的幂等设计:
- 客户端生成唯一请求ID(orderId)
- 服务端拼接幂等Key:
"STOCK:" + orderId + ":" + 当前时间格式化字符串 - 在数据库uk_idem唯一索引上实现防重
支付回调验签的逻辑则是:
- 将回调参数按固定顺序拼接(包含时间戳字符串)
- 使用SHA256计算签名
- 与服务端计算的签名比对
