生产环境大文件上传启动后停滞数分钟该如何排查解决?
可能的原因
- Hetzner 默认DDoS流量清洗机制触发:Hetzner对入向大流量会默认启动清洗逻辑,大文件上传初期的高带宽会被判定为可疑流量,先拦截检测几分钟,确认是正常流量后才会放行,这是Hetzner服务器非常常见的大流量上传/下载初期卡顿的诱因,而DigitalOcean没有这类默认的前置清洗规则,所以staging环境正常。
- 操作系统内核TCP参数默认值差异:虽然你用Ansible管理应用层配置,但如果没有显式配置内核网络参数,Ubuntu 18.04和20.04的默认TCP参数存在差异:比如默认拥塞控制算法、
tcp_wmem/tcp_rmem缓冲区大小、netdev_max_backlog网卡队列长度等,大文件上传时这些参数的不足会导致大量丢包重传,出现初期停滞。 - Nginx临时请求体写入卡顿:当上传文件大小超过
client_body_buffer_size配置值时,Nginx会先把请求体写入磁盘临时目录,若生产服务器的临时目录(默认是/var/lib/nginx/tmp或者/tmp)对应的磁盘IO性能差、存在配额限制、或者目录权限有隐性问题,会导致写入阶段耗时过长,看起来就是上传初期停滞。 - 网卡offload配置异常:Ubuntu 18.04默认开启的部分网卡卸载功能(比如TSO、GRO)和Hetzner的网卡驱动存在兼容性问题,大文件传输时会出现包分片异常,导致大量重传。
排查步骤
- 先验证流量清洗问题:上传大文件时同时监控服务器入向流量,用
tcpdump抓包看初期是不是有大量丢包、重传,同时登录Hetzner控制台看对应的服务器是不是有DDoS清洗事件的记录。 - 对比两台服务器的内核参数:分别在两台机器执行
sysctl -a | grep -E 'tcp_(wmem|rmem|congestion_control)|net.core.(somaxconn|netdev_max_backlog)',核对输出参数是否一致,Ubuntu 18.04的默认值普遍比20.04小很多。 - 测试临时目录IO性能:在生产服务器执行
dd if=/dev/zero of=/tmp/test bs=1G count=1 oflag=direct测试磁盘写入速度,同时检查Nginx临时目录的权限,确认Nginx运行用户有读写权限。 - 检查网卡offload配置:执行
ethtool -k 你的网卡名(比如eth0)看TSO、GRO、GSO等配置是否开启,尝试临时关闭这些配置后再测试上传速度。
对应解决方案
- 如果是Hetzner流量清洗问题:可以在Hetzner控制台调整流量清洗的阈值,或者发工单联系Hetzner申请放宽对应服务器的清洗规则,也可以把大文件上传逻辑改成切片上传,降低单次上传的带宽峰值,避免触发清洗。
- 如果是内核参数差异:在Ansible中增加内核参数配置,把生产服务器的相关TCP参数调整到和staging一致,示例配置如下:
net.core.somaxconn = 1024 net.core.netdev_max_backlog = 10000 net.ipv4.tcp_congestion_control = bbr net.ipv4.tcp_wmem = 4096 16384 67108864 net.ipv4.tcp_rmem = 4096 87380 67108864
修改后执行sysctl -p即可生效。
3. 如果是临时目录IO问题:可以把Nginx的client_body_temp_path配置到IO性能更好的磁盘分区,或者适当调大client_body_buffer_size的数值,减少大文件写入临时磁盘的概率。
4. 如果是网卡offload兼容性问题:可以在Ansible中增加开机自动关闭对应offload配置的脚本,比如ethtool -K eth0 tso off gro off gso off。
内容的提问来源于stack exchange,提问作者Ekin Ertaç
相关产品推荐
相关产品推荐

