同样的 GraphQL API 请求,在浏览器中时而响应 500,且无响应数据,时而响应 200,且有响应数据

1、同样的 GraphQL API 请求,在浏览器中时而响应 500,且无响应数据,时而响应 200,且有响应数据。如图1

图1

2、当响应 500 时,无响应数据。决定设置错误级别,以输出更为详细的错误日志。在入口文件 index.php 中,编写如下实现。如图2

图2

ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
ini_set('error_log', '/tmp/php_errors.log');

3、当响应 500 后,查看文件 /tmp/php_errors.log。PHP Fatal error: Allowed memory size of 134217728 bytes exhausted 。内容如下。如图3

图3

/var/www # cd /tmp
/tmp # ls
php_errors.log
/tmp # cat php_errors.log 
[19-Apr-2023 17:12:22 Asia/Shanghai] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes) in /var/www/object/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php on line 262
[19-Apr-2023 17:12:22 Asia/Shanghai] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 65536 bytes) in /var/www/object/vendor/composer/ClassLoader.php on line 571

4、在入口文件 index.php 中,调整内存大小限制为 1000M ,一直响应 200。确认程序中某处内存占用过大。

ini_set('memory_limit', '1000M');

5、编辑 /var/www/object/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php ,在 262 行附近,打印出相应数据输出至日志文件中。如图4

图4

file_put_contents(storage_path() . '/logs/doFetchAll-slice.txt', print_r($slice, true), FILE_APPEND | LOCK_EX);
file_put_contents(storage_path() . '/logs/doFetchAll-queryString.txt', print_r($this->queryString, true), FILE_APPEND | LOCK_EX);
$data = parent::fetchAll(...$slice);
file_put_contents(storage_path() . '/logs/doFetchAll-data.txt', print_r($data, true), FILE_APPEND | LOCK_EX);
/var/www/object/storage/logs # ls -l
total 65604
-rw-r--r--    1 www      www       65711812 Apr 20 01:43 doFetchAll-data.txt
-rw-r--r--    1 www      www          50958 Apr 20 01:43 doFetchAll-queryString.txt
-rw-r--r--    1 www      www           4820 Apr 20 01:43 doFetchAll-slice.txt
-rw-r--r--    1 www      www           4530 Apr 20 01:43 explicabo78.log
/var/www/object/storage/logs # 

6、基于日志文件分析得出原因,在执行 SQL 查询时,未添加 limit 约束,进而将整张表的数据全部查询出来放入了内存中,进而导致内存超出限制。

永夜