现象:
iOS端5月初发现某一版本的发现页接口499失败率增长明显,原因是iOS端产生的499占比过高。后端发现接口中source都是站内信推送带来的流量。
怀疑可能:
- 聚合域名机制存在问题
- HTTP2.0复用TCP,TCP断开导致所有复用的请求断开与后端链接,触发Nginx生成499
- 客户端将未完成的datatask cancel,触发TCP断开,导致499
- Nginx自身保护机制,误认为相同设备短时间相同接口大量请求是攻击行为,自动断开链接产生499 尝试复现操作:
客户端:基线iPhone;版本:12.5.0;场景:端上通过universalLink模拟站内信推送跳转到发现页Tab,调用频率为每秒一次
复现结果:
- 半小时压测,从前端网络接口回调日志没有看到错误,也就是请求全部成功响应;
- 后端日志#1可以发现有5条左右499;
- 前端wireshark日志显示,在后端499时间附近并未发现tcp.flags.fin或是tcp.flags.reset,也就是前端TCP并未断开连接;
- 冷启动时,通过universalLink跳转发现页Tab,短时间出现两次接口调用,一次是进入页面请求接口,另一次是注册制触发请求接口。
尝试优化:
将注册制请求接口时机延迟1.5秒,压测一小时,后端499仅出现2次,相比之前一小时十多次下降明显。
分析:
- 将异常的业务域名从聚合域名云控去除,经过一天观察499趋势并没有变化,所以排除聚合域名机制问题;
- 前端默认异常的业务使用HTTP2.0,LB对异常的业务域名也默认支持HTTP2.0,所以即使走独立域名也仍会走HTTP2.0,HTTP2.0复用TCP导致499无法排除;
- 冷启动时通过站内信跳转发现tab会在短时间连续调用两次发现接口,后一次接口会将前一次未完成datatask cancel,但是经过分析,后端499时间点附近,前端wireshark并没有抓到tcp.flags.fin或是tcp.flags.reset,也就是前端TCP并未断开连接,所以排除前端datatask cancel导致499;
- iOS端可以通过单设备短时间大量请求复现,另外安卓端一个接口,线上也发现单用户短时间大量请求时出现499。另外网上有文章#2分析499有可能是nginx对单设备频繁请求认为不安全然后生成499,所以无法排除Nginx安全设置导致499问题
总结:
猜测Nginx出于安全保护机制,将单设备重复请求认为是攻击,然后断开链接,HTTP2.0因为TCP复用机制导致复用的请求都会出现499。
后续跟进:
- 上层业务需要对短时间重复请求分析是否合理
- 后端研究婴喜爱Nginx安全机制,是否单设备短时间单个接口大量请求导致误认为攻击,然后断开链接。
跟进结论:
把某台Nginx配置proxy_ignore_client_abort on以后,成功率变为100%。