摘要 :Nginx 做反向代理时,需要接收完 upstream 返回的内容才发回给客户端。 当 upstream 返回 > 的内容过长时,需要临时存到磁盘,存盘时可能出现权限异常。

今天傍晚突然收到运维反馈说某 Web 后台突然访问非常慢,打不开页面。

登录服务器查看 Nginx 日志,发现在 Nginx error.log 中包含大量(13: Permission denied) while reading upstream错误:

2019/05/17 19:33:51 [crit] 31237#0: *12624419709 open() "/var/lib/nginx/uwsgi/2/09/0009076092" failed (13: Permission denied) while reading upstream, ...
2019/05/17 19:33:52 [crit] 31239#0: *12624422108 open() "/var/lib/nginx/uwsgi/3/09/0009076093" failed (13: Permission denied) while reading upstream, ...

今天并没有做线上更新,而且后台其他页面正常,只有访问某个模块才出现卡顿。

Google (13: Permission denied) while reading upstream发现,原来 Nginx 做反向代理时,会先把 upstream 返回的内容全部都完后再发送给客户端。 Nginx 做反向代理时,需要接收完 upstream 返回的内容才发回给客户端。 当 upstream 返回的内容长度超过 proxy_temp_file_write_size 时,会先写入本地缓存目录:

Syntax: proxy_temp_file_write_size size;
Default:    
proxy_temp_file_write_size 8k|16k;
Context:    http, server, location

Limits the size of data written to a temporary file at a time, when buffering
of responses from the proxied server to temporary files is enabled.

本地缓存地址与你使用的 proxy 配置有关,比如我们线上使用的是 Debian 8 系统,使用的 proxy 是 uwsgi,所以临时目录是 uwsgi_temp_path ,默认路径就是/var/lib/nginx/uwsgi。如果 Nginx 进程对该目录没有写权限, 则会抛出异常。

查看该目录权限:

$ ls -ldsh /var/lib/nginx/uwsgi
4.0K drwx------ 12 www-data www-data 4.0K Jul 15  2017 /var/lib/nginx/uwsgi

发现目录所有者是www-data,且只有所有者有权限读写该目录。而我们的 Nginx 进程是使用业务账号(非 www-data)运行的,所以当需要写临时目录时就会报错。

通过分析请求的接口的 access 日志发现,该接口返回的 body 大小将近 2M,远超过proxy_temp_file_write_size默认的 16k,所以才触发了这个问题。

为什么今天才突然出现呢,原来接口里面有一个白名单字段,是根据后台导入的白名单文件内容生成的。今天正好有个运维人员上传了一个非常大的白名单列表, 引发了该问题。

扩展: proxy_temp_path 没有权限写入的话也可能触发一个类似的(13: Permission denied)异常:

2008/03/22 09:44:33 [crit] 18223#0: *642 open() "/usr/local/nginx/client_body_temp/0000000002" failed (13: Permission denied)

参考链接:https://github.com/dockerfile/nginx/issues/4