起因

最近想要在博客中增加 Google AdSense,安装了 WordPress 插件,打开博客管理后台时,一直加载不出来。以为开了代理的问题,关掉代理,发现依然打不开。猜想可能是安装的插件有问题,导致加载失败。登录到服务器,查看 nginx 的日志。

错误日志

在 nginx 的 error.log 发现了如下信息FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 32768 bytes) ,排除是插件导致的问题。

这个问题发生的原因是,PHP 程序已耗尽了可允许分配的最大内存 33554432 bytes,也就是 32 MB,尝试分配 32768 字节时发生了致命的错误。那就是说,我们在 php 服务的配置 memory_limit 是 32MB,这个值太小,需要修改该值。

1
2
3
4
019/11/23 14:24:50 [error] 16258#16258: *490568 FastCGI sent in stderr: "PHP message: PHP Fatal error:  Allowed memory size of 33554432 bytes exhausted (tried to allocate 32768 bytes) in /xxx/xxx/xxx/xyz.php on line 1684" while reading response header from upstream, client: 192.198.83.166, server: www.zhoujunwen.com, request: "POST /xmlrpc.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "blog.zhoujunwen.com"
2019/11/23 14:24:53 [error] 16258#16258: *490582 FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 28672 bytes) in /xxx/xxx/xxx/xyz.php on line 115" while reading response header from upstream, client: 67.205.37.93, server: www.zhoujunwen.com, request: "POST /xmlrpc.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "blog.zhoujunwen.com"
2019/11/23 14:31:16 [error] 16258#16258: *490717 FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 28672 bytes) in /xxx/xxx/xxx/xyz.php on line 115" while reading response header from upstream, client: 103.15.50.211, server: www.zhoujunwen.com, request: "POST /xmlrpc.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "blog.zhoujunwen.com"
2019/11/23 14:40:20 [error] 16258#16258: *490855 FastCGI sent in stderr: "PHP message: PHP Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 28672 bytes) in /xxx/xxx/xxx/xyz.php on line 115" while reading response header from upstream, client: 109.95.158.82, server: www.zhoujunwen.com, request: "POST /xmlrpc.php HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000", host: "blog.zhoujunwen.com"

排查

我们通过 php 命令查看系统信息:

1
php  -i | grep mem

在 console 中输出如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
memory_limit => 128 => 128
report_memleaks => On => On
Collecting memory statistics => No
mem_emalloc_count => 0
mem_emalloc_amount => 0
mem_ecalloc_count => 0
mem_ecalloc_amount => 0
mem_erealloc_count => 0
mem_erealloc_amount => 0
mem_efree_count => 0
mem_efree_amount => 0
mem_malloc_count => 0
mem_malloc_amount => 0
mem_calloc_count => 0
mem_calloc_amount => 0
mem_realloc_count => 0
mem_realloc_amount => 0
mem_free_count => 0
mem_free_amount => 0
mem_estrndup_count => 0
mem_strndup_count => 0
mem_estrdup_count => 0
mem_strdup_count => 0
mem_edupl_count => 0
mem_dupl_count => 0

看到这个结果,自动补全黑人问号,什么情况,memory_limit 的值为 128, 也就是 128MB,这个值远远大于 32MB 的。

我们在项目根目录创建一个 test.php 文件,输入内容:

1
2
3
<? php
echo phpinfo();exit;
<php

在浏览器中查看:http://xxx.xxx.com/index.php

phpinfo输出信息

从页面反馈的信息可以看出,PHP的配置文件是/usr/local/php/etc/php.ini,我们使用 vim 从服务器端打开该文件:

1
vim /usr/local/php/etc/php.ini

在vim编辑器中,在命令模式下,通过?memory_limit搜索配置项,发现该配置项的值确实是 128,和通过 PHP 命令查看到的信息一致。这说明,PHP的配置没有问题,问题可能在 php-fpm 中,找到 php-fpm 的配置文件:/usr/local/php/etc/php-fpm.conf,当然,如果不知道 php-fpm.conf 文件在什么地方,可以通过名find / -name php-fpm.conf 来查看确定位置。

同样通过 vim 打开 php-fpm.conf 文件,在里面查找 memory_limit 关键字,很遗憾,发现并没有这个配置项。此时是不是有点失望呢?别气馁,仔细看看 php-fpm.conf 这个文件,就会发现如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
;;;;;;;;;;;;;;;;;;;;
; Pool Definitions ;
;;;;;;;;;;;;;;;;;;;;

; Multiple pools of child processes may be started with different listening
; ports and different management options. The name of the pool will be
; used in logs and stats. There is no limitation on the number of pools which
; FPM can handle. Your system will tell you anyway :)

; Include one or more files. If glob(3) exists, it is used to include a bunch of
; files from a glob(3) pattern. This directive can be used everywhere in the
; file.
; Relative path can also be used. They will be prefixed by:
; - the global prefix if it's been set (-p argument)
; - /usr/local/php otherwise
include=/usr/local/php/etc/php-fpm.d/*.conf

那么在 /usr/local/php/etc/php-fpm.d/ 目录下一次查看 后缀为 .conf的文件,查找是否有 memory_limit 关键字:

1
2
3
4
5
6
7
; Default Value: nothing is defined by default except the values in php.ini and
; specified at startup with the -d argument
;php_admin_value[sendmail_path] = /usr/sbin/sendmail -t -i -f www@my.domain.com
php_flag[display_errors] = off
php_admin_value[error_log] = /usr/local/php/var/log/www-php-errors.log
php_admin_flag[log_errors] = on
php_admin_value[memory_limit] = 32M

我们在其中一个配置文件中发现了 php_admin_value[memory_limit] = 32M 配置项,没错,这个就是 phpinfo 输出信息中显示的 32M 的内存。我们将其改为 128M,保存。

重启 php-fpm 和 nginx:

1
2
3
4
5
6
7
8
9
# 查看 php-fpm的进程号
ps -ef| grep php-fpm
# ${PHP_FPM_PID} 就是上面上到的进程号,替换一下
kill -USR2 ${PHP_FPM_PID}
# 重启 php-fpm
php-fpm -c /usr/local/php/etc/php.ini -y /usr/local/php/etc/php-fpm.conf

# 重启 nginx
nginx -s reload