问题:为什么使用该选项的 NFS 挂载sync
会导致 nginx 和/或 Chrome(以及仅有的Chrome;而不是 Safari、Firefox、Edge 或 curl)来分块或重新启动文件上传?
背景信息:
我在服务器集群前面有 nginx。我们添加了文件上传,并使用 nginx 来处理上传,然后传递通过 X-FILE 头上传文件主体。
直到最近,我们才在 nginx 服务器上处理上传,因为集群中的其他应用程序服务器无法访问client_body_temp_path
(/tmp
在本例中)。
我们在 AWS 上运行,因此我配置了一个远程教育(又名 NFS)共享并将其挂载在/mnt/efs
,然后将 nginx 更改client_body_temp_path
为指向/mnt/efs/tmp
。
我在所有应用程序服务器上安装了 NFS 共享,现在它们可以访问文件上传/mnt/efs/tmp
,但由于 NFS 异步写入,上传的文件在被其他客户端首次读取时通常为零长度。
我仅在 nginx 服务器上更改了 NFS 挂载,因此它使用以下命令挂载sync
:
初始挂载:
example.eu-west-1.amazonaws.com:/ /mnt/efs nfs4 vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev,nofail
新坐骑:
example.eu-west-1.amazonaws.com:/ /mnt/efs nfs4 vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport,_netdev,nofail,sync
我重新安装了共享并尝试了一些上传和快乐的日子,其他 NFS 客户端看到了非空文件/mnt/efs/tmp
。
但经过进一步测试,结果发现上传超过 10M 的文件被 Chrome 重启或分块。
会发生什么:
nginx 开始接收上传(在下面的视频中,我正在发送一个 32.7MB 的文件),但在 6.4MB 时,新的上传开始,然后最终 nginx 决定客户端停止发送,因此出现问题A499
这会导致 Chrome 中止上传,并且一切都会失败。您可以在此处看到所有发生的情况,因为我watch
将文件传入/mnt/efs/tmp
:
http://jay.gooby.org/media/video/chrome%20failing.mp4
上传最初为,0000000006
但当达到 6.4M 时,第二次上传0000000007
开始(但0000000006
继续到 12M),然后当0000000007
达到 6.4 时,第三次0000000008
上传开始(0000000007
继续到 12M)。一旦0000000008
达到 12M,ngingx 就会发出499
,Chrome 会中止上传。
其他用户代理没有这个问题。我能够使用 Safari、Firefox 和 curl 上传同一个文件。Mac 和 Windows 上的 Chrome 都存在同样的问题。
以下是 curl 发送文件时没有任何问题的情况:它以0000000010
单个 32M 文件的形式到达:
http://jay.gooby.org/media/video/curl%20working.mp4
经过一番折腾,我sync
从 nginx 服务器上的 NFS 挂载中删除了该选项,结果,使用 Chrome 上传的文件竟然以单个文件的形式完整地到达了。那么到底是怎么回事呢?
nginx 位于弹性 IP 后面,但不位于 ELB 后面,并且上传通过 http2 进行。
nginx 编译时使用--with-threads
选项
更新 1: 6.4mb 这个值似乎很重要,因为这是每个新上传块开始/重新开始的点。6.4mb 是 51200000 位,这似乎是一个非常具体的值......
这三个文件的初始字节相同,因此就好像 Chrome 决定从 6.4mb 点开始重新发送: