记录一次解决PHP返回数据被nginx截断的问题

来源:互联网 发布:mac设置airdrop 编辑:程序博客网 时间:2024/05/22 10:53

前言

今日,发生了一件懵逼的事情,通过内部接口获取数据的时候,概率性出现返回的数据被截断的问题。内部接口好好的为何突然出现问题了?此文将记录这次本应该很快解决却没有很快解决的过程。

正文

背景

内部接口分为5+3=8台机器,为什么这么说呢,5台是一直有的,而3台是刚新增的,问题就出在了这三台,由于负载均衡策略所以出现在前文说到的概率性出现返回的数据被截断的问题。

一般开发是没有机器权限的,在不申请临时机器权限的情况下。解决速度完全取决于运维,无果。

发现过程

1.先是四处埋点记日志,确认原因是日志被截断了。
2.由于无线上机器权限所以只好通过跳板机到拟真环境进行

curl -H 'Host:internal.xxx.com' '192.168.xx.xx/data/get_list.json?xxx=xxx'

操作来定位哪台机器出问题了。
是的,8台机器都试过去发现,真的是新增的3台有问题。
3.进一步确认机器上nginx的error日志报错了一堆:

2016/06/07 00:41:28 [crit] 32763#0: *5439 open() "/usr/local/nginx/fastcgi_temp/5/02/0000000025" failed (13: Permission denied) while reading upstream, client: 203.171.237.2, server: internal.xxx.com, request: "GET /xxx/xxx.json HTTP/1.0", upstream: "fastcgi://127.0.0.1:9000",...

好了,到现在基本可以得出结论是nginx导致的。

分析截断产生原因

看报错显示是fastcgi_temp的写入没权限?
有点懵逼,这个和fastcgi_temp什么关系?
经过查资料得到:
原来nginx存在一个buffer的机制,数据过大超出缓冲区的最大容量,会将数据写入临时文件时(fastcgi_temp目录下),而此时又没有权限,所以再返回时,超出缓冲区的数据将丢失,就出现了截断。

解决办法

先是查询nginx的配置

user www   //此处的意思是nginx 使用root 的权限,解决问题1head{    fastcgi_buffers 4 64k;//此处值代表nginx 设置 4个 32k 的块进行缓存,总共大小为4*64k     fastcgi_buffer_size 64k;//磁珠值代表每块大小}

给fastcgi_temp 目录赋读写权限

sudo chown -R www:root fastcgi_tempchmod -R 764 /usr/local/nginx/fastcgi_temp/

nginx的buffer机制

对于来自 FastCGI Server 的 Response,Nginx 将其缓冲到内存中,然后依次发送到客户端浏览器。缓冲区的大小由 fastcgi_buffers 和 fastcgi_buffer_size 两个值控制。
比如如下配置:

fastcgi_buffers 4 64k;fastcgi_buffer_size 64K;

fastcgi_buffer_size : 用于指定读取FastCGI应答第一部分需要用多大的缓冲区,这个值表示将使用1个64KB的缓冲区读取应答的第一部分(应答头),可以设置为fastcgi_buffers选项指定的缓冲区大小。

fastcgi_buffers : 指定本地需要用多少和多大的缓冲区来缓冲FastCGI的应答请求。如果一个PHP脚本所产生的页面大小为256KB,那么会为其分配4个64KB的缓冲区来缓存;如果页面大小大于256KB,那么大于256KB的部分会缓存到fastcgi_temp指定的路径中,但是这并不是好方法,因为内存中的数据处理速度要快于硬盘。一般这个值应该为站点中PHP脚本所产生的页面大小的中间值,如果站点大部分脚本所产生的页面大小为256KB,那么可以把这个值设置为“16 16k”、“4 64k”等。

所以总计能创建的最大内存缓冲区大小是 4*64K+64K = 320k。而这些缓冲区是根据实际的 Response 大小动态生成的,并不是一次性创建的。比如一个 128K 的页面,Nginx 会创建 2*64K 共 2 个 buffers。

当 Response 小于等于 320k 时,所有数据当然全部在内存中处理。如果 Response 大于 320k 呢?fastcgi_temp 的作用就在于此。多出来的数据会被临时写入到文件中,放在这个目录下面。
内存中缓冲了 320K,剩下的会写入的文件中。而实际的情况是,运行 Nginx Process 的用户并没有 fastcgi_temp 目录的写权限,于是剩下的数据就丢失掉了。