升级操作系统、Apache及PHP后,PHP流式输出Shell脚本执行结果的Chunk Size/数据量异常问题
这种升级后实时流式输出突然变成批量吐数据的情况真的挺闹心的,毕竟之前都是Shell脚本输出一行,浏览器就实时显示一行,现在要等攒够好几行才一起出来,完全没了实时性。结合你已经排除了PHP版本和浏览器的问题,咱们重点从Apache和操作系统层面的缓冲、传输优化配置入手排查,大概率是这俩地方的默认设置变了搞的鬼:
先查Apache的输出压缩(mod_deflate)配置
新环境的Apache很可能默认开启了对HTML、文本类输出的gzip压缩,而压缩模块为了提高压缩效率,会先缓冲一定量的数据再进行压缩发送——这就是你看到“攒够5行才一起输出”的核心原因之一。
你可以先检查Apache的主配置文件(httpd.conf)或者对应虚拟主机的配置,看看有没有类似AddOutputFilterByType DEFLATE text/html text/plain的配置项。
解决办法也很直接:- 在你的PHP脚本开头加上
header('Content-Encoding: none');,强制告诉Apache和浏览器不要对这个请求启用压缩; - 或者在Apache配置里给这个脚本的路径单独禁用压缩:
SetEnvIf Request_URI "^/你的脚本路径.php$" no-gzip=1
- 在你的PHP脚本开头加上
再看Apache自身的输出缓冲区大小
Apache有个OutputBufferSize参数,控制着它会先缓冲多少字节的输出内容,才会推送给客户端。如果新环境这个参数的值比旧环境大(比如旧环境是1K,新环境改成了8K),自然就需要攒够更多数据才会发送。
你可以在Apache配置里搜索这个参数,默认值可能是8192(8KB),如果新环境设得更大,就会导致这个问题。
解决办法:在虚拟主机配置或者httpd.conf里把这个值改小,比如OutputBufferSize 1024(1KB),部分Apache版本支持设为0直接禁用这个缓冲,你也可以试试。排查操作系统的TCP套接字优化(Nagle算法)
新升级的操作系统可能默认开启了TCP的Nagle算法,这个算法的作用是合并多个小数据包来减少网络开销,但代价就是会延迟小数据的发送——刚好匹配你遇到的“Shell脚本输出单行后要等几秒才会被推送”的情况。
另外Apache的EnableSendfile功能在新环境也可能默认开启,它和Nagle算法叠加的话,缓冲效果会更明显。
你可以在Apache配置里添加这两行试试:EnableSendfile Off TCP_NODELAY On第一行关闭Sendfile优化,第二行禁用Nagle算法,让小数据包可以实时被推送。
最后再确认下PHP的缓冲配置(保险起见)
虽然你说降级PHP后问题依旧,但新环境的php.ini配置可能和旧环境不一样,还是顺手检查下:- 找到
output_buffering项,确保它设为Off或者一个很小的值(比如4096以下); - 找到
implicit_flush项,设为On,这样PHP每次输出内容后都会自动刷新内部缓冲; - 如果你的PHP脚本是用
proc_open来实时读取Shell输出的,记得每读取一行后都调用ob_flush(); flush();,确保把数据层层推送到Apache。
- 找到
备注:内容来源于stack exchange,提问作者Ayad

