MySQL代码导致PHP脚本在popen/exec时崩溃 [英] MySQL code causes PHP script to crash at popen/exec
问题描述
我在Ubuntu 14.04
服务器上具有以下PHP 5.6.19
代码.这段代码只是连接到MySQL 5.6.28
数据库,等待一分钟,本身启动另一个进程,然后退出.
I have the following PHP 5.6.19
code on a Ubuntu 14.04
server. This code simply connects to a MySQL 5.6.28
database, waits a minute, launches another process of itself, then exits.
注意:这是完整的脚本,目的是演示问题-它没有做任何有用的事情.
Note: this is the full script, and it's purpose is to demonstrate the problem - it doesn't do anything useful.
class DatabaseConnector {
const DB_HOST = 'localhost';
const DB_NAME = 'database1';
const DB_USERNAME = 'root';
const DB_PASSWORD = 'password';
public static $db;
public static function Init() {
if (DatabaseConnector::$db === null) {
DatabaseConnector::$db = new PDO('mysql:host=' . DatabaseConnector::DB_HOST . ';dbname=' . DatabaseConnector::DB_NAME . ';charset=utf8', DatabaseConnector::DB_USERNAME, DatabaseConnector::DB_PASSWORD);
}
}
}
$startTime = time();
// ***** Script works fine if this line is removed.
DatabaseConnector::Init();
while (true) {
// Sleep for 100 ms.
usleep(100000);
if (time() - $startTime > 60) {
$filePath = __FILE__;
$cmd = "nohup php $filePath > /tmp/1.log 2>&1 &";
// ***** Script sometimes exits here without opening the process and without errors.
$p = popen($cmd, 'r');
pclose($p);
exit;
}
}
我使用nohup php myscript.php > /tmp/1.log 2>&1 &
开始脚本的第一个过程.
I start the first process of the script using nohup php myscript.php > /tmp/1.log 2>&1 &
.
该进程循环应该永远持续下去,但是...基于一天内的多次测试(但不是立即),服务器上的进程会消失",没有任何理由.我发现MySQL
代码导致popen
代码失败(脚本退出,没有任何错误或输出).
This process loop should go on forever but... based on multiple tests, within a day (but not instantly), the process on the server "disappears" without reason. I discovered that the MySQL
code is causing the popen
code to fail (the script exits without any error or output).
这是怎么回事?
注释
- 服务器运行24/7.
- 内存不是问题.
- 数据库正确连接.
- 文件路径不包含空格.
- 使用
shell_exec
或exec
代替popen
(和pclose
)时,存在相同的问题.
- The server runs 24/7.
- Memory is not an issue.
- The database connects correctly.
- The file path does not contain spaces.
- The same problem exists when using
shell_exec
orexec
instead ofpopen
(andpclose
).
我还知道popen
是失败的行,因为我通过在脚本中的某些位置登录到文件来进行了进一步的调试(未在上面显示).
I also know that popen
is the line that fails because I did further debugging (not shown above) by logging to a file at certain points in the script.
推荐答案
父进程在分叉之后是否肯定退出?我以为pclose
会等孩子离开后再返回.
Is the parent process definitely exiting after forking? I had thought pclose
would wait for the child to exit before returning.
如果它没有退出,我推测是因为mySQL连接从未关闭,因此您在生成子进程树时最终会达到其连接限制(或其他限制).
If it isn't exiting, I'd speculate that because the mySQL connection is never closed, you're eventually hitting its connection limit (or some other limit) as you spawn the tree of child processes.
编辑1
我刚刚尝试复制此内容.我将您的脚本更改为每半秒而不是每分钟进行一次分叉,并能够在大约10分钟内将其杀死.
I've just tried to replicate this. I altered your script to fork every half-second, rather than every minute, and was able to kill it off within about 10 minutes.
子进程的重复创建似乎正在生成越来越多的FD,直到最终它不再具有更多的FD:
It looks like the the repeat creation of child processes is generating ever more FDs, until eventually it can't have any more:
$ lsof | grep type=STREAM | wc -l
240
$ lsof | grep type=STREAM | wc -l
242
...
$ lsof | grep type=STREAM | wc -l
425
$ lsof | grep type=STREAM | wc -l
428
...
那是因为孩子在派生时继承了父母的FD(在本例中为mySQL连接).
And that's because the child's inheriting the parent's FDs (in this case for the mySQL connection) when it forks.
如果在popen
之前使用(在您的情况下)关闭mySQL连接:
If you close the mySQL connection before popen
with (in your case):
DatabaseConnector::$db = null;
问题有望解决.
这篇关于MySQL代码导致PHP脚本在popen/exec时崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!