我们有一个 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
这可能与以下情况有关:
- https://500.keboola.com/cp-in-docker-cannot-allocate-memory-part-2-369490f1a88f
- https://github.com/docker/for-linux/issues/651
- https://github.com/kubernetes/kubernetes/issues/43916
- https://bugzilla.kernel.org/show_bug.cgi?id=207273
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)
可能的解决方法似乎是:
- 要么大幅降低 vm.dirty 阈值,但这是针对每个主机,而不是每个容器,这可能会对性能产生影响
- 或者大幅增加所有执行磁盘 IO 的容器的内存限制......
- 等待 docker/kubernetes 中集成的 cgroup v2,参见未来的 docker 20.03 和https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20191118-cgroups-v2.md