一次,在线上后台导出了比平时多几倍的数据,发现导出了部分之后停止了,出现失败-网络错误的提示:
导出的核心代码是这样的
set_time_limit(0);
ini_set('memory_limit', '256M');
header("Content-type:text/csv;charset=UTF-8");
header('Content-Encoding: UTF-8');
header('Content-Disposition: attachment;filename=' . $fileName . '.csv');
header('Cache-Control:must-revalidate,post-check=0,pre-check=0');
header('Expires:0');
header('Pragma:public');
// 打开php标准输出流
$fp = fopen('php://output', 'a');
// 添加BOM头,以UTF8编码导出CSV文件,如果文件头未添加BOM头,打开会出现乱码。
fwrite($fp, chr(0xEF).chr(0xBB).chr(0xBF));
// 添加导出标题
fputcsv($fp, $titleFields);
// 导出内容
$curl = app('curl');
$params['page'] = 1;
$params['limit'] = 1000;
do {
$result = $curl->get($uri, $params);
$params['page']++;
if (empty($result['data']['list'])) {
break;
}
foreach ($result['data']['list'] as $item) {
fputcsv($fp, $item);
}
// 每获取一页数据就输出到浏览器中
ob_flush();
flush();
} while (!empty($result['data']['list']));
exit(0);
刚开始怀疑是不是内存溢出导致的,那就去查看php的错误日志,但并没有发现Fatal error: Allowed memory size of xx bytes exhausted...之类的报错。
接着查看业务日志,有没有捕获到异常,也没有发现!
这个时候只能静下来梳理下这个过程:
导出请求 -> 服务器 -> nginx -> php -> 导出文件
其中nginx通过fastcgi协议和php进行通信,php通过php-fpm进程处理nginx的请求。
查看nginx的访问日志,发现了导出请求,请求参数也正常。
接着查看nginx的错误日志,发现有这样的报错:
2022/12/13 10:48:50 [error] 34#34: *29 readv() failed (104: Connection reset by peer) while reading upstream...
从字面上猜测,nginx和php的通信被迫断开了,到底是nginx主动断开,还是php主动断开呢?
假设是nginx主动断开,那么就需要查看相关的fastcgi的配置了:
# fastcgi_buffers表示需要用多少个多大的缓冲区缓冲fastcgi的响应
fastcgi_buffers 256 4k;
# fastcgi_buffer_size表示指定读取FastCGI应答第一部分需要多大的缓冲区
fastcgi_buffer_size 4k;
# fastcgi_busy_buffers_size默认是fastcgi_buffers两倍
fastcgi_busy_buffers_size 256k;
# 表示在写入缓存文件时使用多大的数据块,默认值也是fastcgi_buffers的两倍
fastcgi_temp_file_write_size 256k;
然后把相关参数进行调高,发现并没有效果!暂时排除nginx的问题。
接下来查看php的配置,由于是断开连接,可能是超时导致的,所以先查看:
php.ini:
max_execution_time = 30
php-fpm:
request_terminate_timeout = 5
其中,max_execution_time表示脚本执行的最大时间(这里只会统计php代码执行时间,对于sleep、数据库操作、流操作等带来的时间消耗是不包括的),request_terminate_timeout表示php-fpm进程的最大存在时间。
这两个配置都会导致超时的发生!如果max_execution_time足够大,request_terminate_timeout配置过小,可能发生php-fpm进程被杀掉,这里会记录一个php-fpm的日志;如果request_terminate_timeout足够大,max_execution_time配置过小,可能发生脚本没执行完就断开了,这里也会记录一个php错误日志。
接着把request_terminate_timeout的值调高,问题得到了解决!
标签:php,网路,buffers,header,导出,nginx,线上,csv,fastcgi From: https://www.cnblogs.com/xiaoxiaobug/p/16987986.html