为什么 nginx 在代理非常大的文件时会抛出 `4023 pwrite()` 错误

为什么 nginx 在代理非常大的文件时会抛出 `4023 pwrite()` 错误

我们有一个 nginx 守护进程,它充当我们微服务的代理服务器。我们有 2 个 nodejs 服务器,中间有一个 nginx 代理。

当服务器 A 将大型 CSV 发布到服务器 B 时,我们收到以下错误”

 2019/06/24 14:02:50 [crit] 8#8: *4023 pwrite() "/var/cache/nginx/client_temp/0000000004" failed (12: Cannot allocate memory), client: 172.1.0.11, server: , request: "POST /core/api/source/upload HTTP/1.0", host: "web_core". 

我们已将以下内容应用于我们的服务器块:

    proxy_request_buffering off;
    proxy_connect_timeout 600;
    proxy_send_timeout 600;
    proxy_read_timeout 600;
    send_timeout 600;
    client_max_body_size 0;

我们如何配置服务器和 nginx 来正确代理大文件?

答案1

这不是 nginx 问题。帮助我调试此问题的内容:

4023 不相关 - 它是一个 ID

pwrite() 是一个系统调用

我找到了 nginx 工作进程的 PID,并运行cat /proc/$PID/limits并验证它已分配内存。

检查完所有这些后,我重新评估了网络配置,并确定问题出在上游 nginx 服务上,该服务的内存限制小于有效负载。

答案2

这可能与以下情​​况有关:

TL;DR 似乎默认脏内存写回阈值在内存限制较低的容器中触发得太晚,因此写入文件可能会导致内存错误。

(因为脏页已计入内存限制)(然后write返回ENOMEM/12/ cannot allocate memory,或者内核在进程上调用 OOMKiller,可能在较新的内核版本中;我pwrite ENOMEM在 linux 4.14 中得到了这个)

发生这种情况的原因似乎是 docker/kubernetes 使用 cgroup v1,其vm.dirty_ratio阈值似乎是根据主机总内存(可用)而不是预期的 cgroup/container-local(可用)内存计算的。=> 如果内存限制相对于主机总可用内存较低,则脏页是不是照常写回,写入期间达到内存限制。(随着未来 cgroup v2 在 docker/kubernetes 中的集成和最新的内核,这个问题应该可以得到解决,至少对于大多数 fs、cfhttps://github.com/torvalds/linux/blob/a1d21081a60dfb7fddf4a38b66d9cef603b317a9/Documentation/admin-guide/cgroup-v2.rst#writeback

可能的解决方法似乎是:

相关内容