下单接口偶尔五零四,用户看到失败就刷新重下,事后库里出现两笔一模一样的订单,而后端日志显示那次被判超时的请求在二十秒后仍然返回了成功。
排查方向其实有限,先把可能性排一排。nginx 的 proxy_next_upstream 把超时也算成可重试,同一请求被发到了另一台后端;五零四只代表网关不再等,后端进程并没有被打断,仍在继续执行;客户端超时后用户手动重试,服务端没有任何幂等判断;订单号在服务端生成,两次请求各自生成一个新号,查重也拦不住。
动手时先确认重试策略里包含了哪些条件
grep -n 'proxy_next_upstream' /etc/nginx/nginx.conf /etc/nginx/conf.d/*.conf
接着把超时从可重试条件里摘出去
sed -i 's/proxy_next_upstream .*/proxy_next_upstream error http_502;/' /etc/nginx/conf.d/order.conf && nginx -t && nginx -s reload
然后核查已经产生的重复单
mysql -e 'select order_no,count(*) as c from orders group by order_no having c>1 limit 20;'
剩下的就是按幂等键重放两次确认只写一笔
curl -s -H 'Idempotency-Key: probe-20261109' -d 'sku=1001' http://127.0.0.1:8080/order
改完先别撤,确认这几项。同一个幂等键连发两次只生成一笔订单,nginx 日志里五零四不再伴随重试记录,订单表的重复计数查询返回空集。
补一句。网关超时不等于业务失败,凡是会写数据的接口都要有幂等键,光靠前端禁用按钮挡不住用户刷新。这类问题最好一次改到位,反复小改反而容易把原因搅混。
