Nginx 502 Bad Gateway。通过增加缓冲区解决问题。为什么?

21

我正在设置一个LEMP堆栈来运行Drupal。我安装了Nginx和PHP-FastCGI。

Nginx运行正常,但是任何尝试运行PHP都会出现"502 Bad Gateway"的错误。

快速谷歌搜索得知:nginx 502 bad gateway,增加缓冲区大小解决了这个问题。

fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;

问题是为什么?

我的理解

从之前的链接中可以看出,nginx正在向PHP-FastCGI发送请求,但它没有响应。这些请求有什么特殊之处导致它超时呢?

是因为php代码过于复杂而没有足够的时间来响应(实际上不是,它只是phpinfo();)。现在我已经增加了缓冲区,那么什么情况下需要再次增加缓冲区呢?


我在某些 PHP 调用中遇到了相同的 Nginx 502 错误网关问题,添加缓冲区和缓冲区大小对我也起作用。不确定原因。 - amurrell
1
这是一个好问题,只是在错误的论坛上提问。我也一直在思考这个问题,很烦恼每个解决方案都是增加缓冲区大小而没有说明原因。多大才算太大?太小又有什么影响?为什么这不是默认配置?为什么?为什么?为什么? - jpeltoniemi
1
请查看此链接:https://gist.github.com/magnetikonline/11312172#determine-fastcgi-response-sizes - Neo
3个回答

14
如果您检查nginx错误日志,很可能会看到这个消息:
上游从上游读取响应头时发送的标头过大

fastcgi_buffers设置用于FastCGI上游响应的缓冲区段的数量和内存大小。
文档中提供的默认值为:
fastcgi_buffers 8 4k|8k;
其中默认缓冲区大小等于您操作系统的页面大小。
getconf PAGESIZE可获取当前内存页大小。
例如,在Ubuntu 14.01中,默认页面大小为4KB。 这意味着您有8个段,每个段为4KB。总共32KB。 FastCGI的响应超过了这个数字,这就是我们收到响应代码502 - 服务器已接收的原因。
这不是一个很好的解释,但我希望能帮助您更好地理解。

那么,如何知道FastCGI响应的大小? - Fahmi
这取决于您的应用程序,我猜; fpm处理请求并呈现HTML输出,nginx接收。该输出的大小大于fastcgi缓冲区。 - antonbormotov
@antonbormotov 它缓冲整个响应,还是只缓冲第一个块、响应头? - Thomas Decaux
1
据我所知,fastcgi_buffers缓冲区是用于缓存响应体或其前几个块(如果响应大小更大),而fastcgi_buffer_size则是用于缓存响应头。@ThomasDecaux - antonbormotov

8
实际上,这个问题只与fastcgi_buffer_size直接相关。这是一个非常特殊的缓冲区,仅保存来自响应的HTTP头部。
如果您的应用程序发出大量Set-Cookie头(或其他有助于HTTP头部总大小的内容),则此处的默认缓冲区大小可能不足,您需要增加它。
为了理解如何增加它,您可以阅读我超级详细的文章这里 - 它是关于proxy_buffer_size,但fastcgi_缓冲区的行为非常相似。引用基本命令:
curl -s -w \%{size_header} -o /dev/null https://example.com

确保针对正确的URL进行测试,并通过-H添加请求头(如果需要)。

这将为您提供以字节为单位的标头大小。然后,您需要将结果值与4k(内存页的典型大小)对齐。

因此,如果您得到了例如14342个字节,则需要设置:

fastcgi_buffer_size 16k;

其中关键的部分并不在这里,而是当您增加此缓冲区大小时,由于NGINX使用/计算后者的默认值的方式,您需要同时增加fastcgi_buffer_size和/或fastcgi_busy_buffers_size

无论哪种方式,都不要将这些缓冲区设置得太高,并使用特定于您的应用程序的计算。任意高的值对您的RAM不利,因为这些缓冲区是每个连接使用的。


5
问题实际上可能与容器中的权限有关(我们在Alpine上遇到了这个问题,但其他发行版也可能是同样的情况),位于/var/lib/nginx/tmp目录下。该目录由nginx用户拥有,并且仅可由nginx组进行写操作。当请求缓冲区超过缓冲区大小时,会将/var/lib/nginx/tmp用作临时写入位置,直到足够的缓冲区释放以完成请求为止。对tmp目录进行写入请求的是www-user(同样在Alpine Linux中),该用户没有权限向该位置写入。
如果您查看Nginx的预安装脚本(适用于Alpine Linux),您会发现nginx组正在添加到www-data组中。这是必需的安装,因为nginx用户负责安装和启动Nginx实例。之后,所有Nginx职责都交给www-data用户来处理通过容器传输的http流量。为了让www-data用户能够写入到/var/lib/nginx/tmp目录中,需要更改目录的所有权,使其属于www-data用户或者将www-data用户添加到nginx组中(可能会引起安全问题)。
我在Nginx仓库上创建了一个问题,该问题更好地解释了此问题,并提供了解决Alpine Linux的解决方法:https://gitlab.alpinelinux.org/alpine/aports/-/issues/12669 虽然这是一个Alpine Linux的问题,但我怀疑其他遇到此问题的人也面临类似的权限问题。有关Nginx如何运作的文档可以在这里找到。
尽管这个问题很旧,但我们最近遇到了这个问题,并花了大约一周的时间来解决它,因为简单地增加缓冲区大小似乎不是我们的长期解决方案。希望这能让别人免去一周的头痛,试图找到同样的解决方案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接