分析 fastcgi_temp 错误以及 Nginx 的 Buffer 机制
最近在使用 phpMyAdmin 的时候,发现一个很让人蛋疼的问题,在每次修改表结构时,页面没有载入完成就自动停止了。因为一直使用 svn/trunk 版本的 PMA,开始以为是程序的问题,但是换成 stable 版本后,问题依旧存在,显然走错了方向。于是再查 error.log,终于找到的症结所在。
日志中显示类似下面的错误:
2010/03/13 02:52:19 [crit] 3396#0: *10 open()
"/usr/local/nginx/fastcgi_temp/2/00/0000000002" failed (13: Permission denied)
看起来是权限问题,要完全的解决这个问题,先要搞清楚 fastcgi_temp 目录的作用。
先简单的说一下 Nginx 的 buffer 机制,对于来自 FastCGI Server 的 Response,Nginx 将其缓冲到内存中,然后依次发送到客户端浏览器。缓冲区的大小由 fastcgi_buffers 和 fastcgi_buffer_size 两个值控制。
比如如下配置:
fastcgi_buffers 8 4K;
fastcgi_buffer_size 4K;
fastcgi_buffers 控制 nginx 最多创建 8 个大小为 4K 的缓冲区,而 fastcgi_buffer_size 则是处理 Response 时第一个缓冲区的大小,不包含在前者中。所以总计能创建的最大内存缓冲区大小是 8*4K+4K = 36k。而这些缓冲区是根据实际的 Response 大小动态生成的,并不是一次性创建的。比如一个 8K 的页面,Nginx 会创建 2*4K 共 2 个 buffers。
当 Response 小于等于 36k 时,所有数据当然全部在内存中处理。如果 Response 大于 36k 呢?fastcgi_temp 的作用就在于此。多出来的数据会被临时写入到文件中,放在这个目录下面。同时你会在 error.log 中看到一条类似 warning:
2010/03/13 03:42:22 [warn] 3994#0: *1 an upstream response is buffered to a temporary file
/usr/local/nginx/fastcgi_temp/1/00/0000000001 while reading upstream,
client: 192.168.2.1,
server: pma.verdana.cn,
request: "POST /tbl_structure.php HTTP/1.1",
upstream: "fastcgi://127.0.0.1:9000",
host: "pma.verdana.cn",
referrer: "http://pma.verdana.cn/tbl_structure.php"
显然,缓冲区设置的太小的话,Nginx 会频繁读写硬盘,对性能有很大的影响,但也不是越大越好,没意义,呵呵!
搞清楚了这些,再回到原来的问题上面,phpMyAdmin 生成的页面大小达到了 100+ Kb,内存中缓冲了 36Kb,剩下的会写入的文件中。而实际的情况是,运行 Nginx Process 的用户并没有 fastcgi_temp 目录的写权限,于是剩下的数据就丢失掉了,这也是为什么 phpMyAdmin 页面只显示了一部分的原因了。
找到原因后,解决方法就比较简单了,粗暴的删掉 fastcgi_temp 目录或者温柔的 chown + chmod 都可以解决问题。
或者修改nginx.conf配置:
fastcgi_buffers 32 16K;
fastcgi_buffer_size 4K;