多进程共用mysql链接引发的一个问题

MYSQL Jenner 9058℃ 0评论

我们知道,每次fork操作系统都会复制进程的所有信息产生一个子进程(部分写时复制),其中就包括socket链接资源符。每个进程在PCB(Process Control Block)中都保存着一份文件描述符表,文件描述符就是这个表的索引,每个表项都有一个指向已打开文件的指针,现在我们明确一下:已打开的文件在内核中用file结构体表示,文件描述符表中的指针指向file结构体。实际上包括文件描述符,socket等资源符号,操作系统并没有真的复制,而是在父子进程之间复制了资源符的指针。

操作系统允许多个进程公用一个socket资源符,但是会有一定的风险。例如:两个进程同一时刻接收服务器发来的响应,就有可能抢读到对方的响应。

今天就遇到了与父子进程共用socket链接的一个问题,先上代码:

$mysql = mysql_connect('127.0.0.1', 'root', '123456');

$process_count = 0;
while(true){
    $pid = pcntl_fork();
    if($pid<0){
        echo "fork error" . PHP_EOL;
    }elseif($pid == 0){
        $process_count++;
        if($process_count > 3){
            pcntl_wait($status);
            $process_count--;
        }
    }else{
        $mysql = mysql_connect('127.0.0.1', 'root', '123456');
        // do something
        exit;
    }
}

我们看到,子进程会重新建立mysql链接,执行完任务后退出。退出时,链接自动关闭。最开始并没有出现问题,运行了过一会,出现了mysql server has gone away的错误。而重新建立mysql链接总是返回false。

后来与人讨论,才想起mysql_connect函数的第四个参数new_link默认为flase,也就是说,在参数相同的情况下,mysql会复用没有关闭的mysql链接。

这里我们回想下,上面的程序fork第一个子进程,由于new_link参数默认为false,所以实际上是复用了父进程的mysql链接,而当这个进程退出时,链接被关闭,mysql关闭会话线程。而父进程再次创建子进程时,同样继承了mysql资源服,而父进程并不知道mysql链接已经被第一个子进程关闭,所以被fork出来的第二个子进程同样不知道mysql链接不可用(服务端已关闭)。于是mysql_connect时依然重用了之前的mysql链接,必然是链接不成功的,返回false。

问题虽然不大,但是折腾了好久,最后总算是弄清楚了原因。

写代码在于折腾。

原创文章,转载请注明: 转载自始终不够

本文链接地址: 多进程共用mysql链接引发的一个问题

转载请注明:始终不够 » 多进程共用mysql链接引发的一个问题

喜欢 (4)
  1. 请问PDO的出现PDOStatement::execute(): Premature end of data (mysqlnd_wireprotocol.c:1244)是什么原因?我也是多进程执行php链接mysql,用的yii2框架