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

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

我们知道,每次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。 问题虽然不大,但是折腾了好久,最后总算是弄清楚了原因。 写代码在于折腾。 原创文章,转载请注明:
Continue reading 多进程共用mysql链接引发的一个问题