一个平凡的下午,突然被拉去 oncall

服务端带宽打满了!兜不住了!业务马上要挂了!

于是紧急开始排查,从 nginx 日志里很快定位到是我们的文件上传接口在刷流量

具体原因这里不展开,现象是合法客户端会不断调用接口上传大文件

这里也不讨论客户端解决方案,因为客户端就算修了也要打包发版推送

当然也不可能像对抗 DDOS 那样用防火墙封 ip,因为服务端只看到了公网 ip,而这很可能是整个工区的出口 ip

而且目前只是流量很费钱,要说把核心业务停下来降温是想都不敢想的 ~

作为服务端,需要的是一个能立即 解决故障缩小影响面 的方案

首先第一反应是阻止重试,尝试构造一些响应来让客户端认为请求成功,别再发包了

可惜不行,客户端 bug 成因比较复杂,尝试半天的结论就是这样做不了

然后就努力尝试中断请求,在客户端发完包之前就阻断,减少上行流量

可惜找了半天也没发现 nginx 有什么好用的配置

而我们短期也不可能给 nginx 写出来一个网络扩展去影响 4 层协议


然后作为一个无法解决的问题开始拉更多人讨论 ~

经过彻夜奋战,得到一个优雅丝滑的方案

TCP 拥塞控制:只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞

因此降低 server 端的处理速度自然可以反作用到网络链路上

当 server 端包处理足够慢,自然就实现了由服务端控制的流量限速

最终的解决方案是 access_by_lua 里注入 ngx.sleep(10)