本篇文章带大家了解一下PHP中的多进程消费队列。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
|
本篇文章带大家了解一下PHP中的多进程消费队列。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。
推荐学习:《PHP视频教程》 最近开发一个小功能,用到了队列mcq,启动一个进程消费队列数据,后边发现一个进程处理不过来了,又加了一个进程,过了段时间又处理不过来了...... 这种方式每次都要修改crontab,如果进程挂掉了,不会及时的启动,要等到下次crontab执行的时候才会启动。关闭(重启)进程的时候用的是kill,这可能会丢失正在处理的数据,比如下面这个例子,我们假设sleep过程就是处理逻辑,这里为了明显看出效果,将处理时间放大到10s: <?php
$i = 1;
while (1) {
echo "开始第[{$i}]次循环\n";
sleep(10);
echo "结束第[{$i}]次循环\n";
$i++;
}当我们运行脚本之后,等到循环开始之后,给进程发送 开始第[1]次循环 结束第[1]次循环 开始第[2]次循环 [1] 28372 terminated php t.php nginx进程模型这时候我想到了nginx,nginx作为高性能服务器的中流砥柱,为成千上万的企业和个人服务,他的进程模型比较经典,如下所示:
管理员通过master进程和nginx进行交互,从 进程设计看了nginx的进模型,我们完全可以开发一个类似的类库来满足处理mcq数据的需求,做到单文件控制所有进程、可以平滑退出、可以查看子进程状态。不需要太复杂,因为我们处理队列数据接收一定的延迟,做到nginx那样不间断服务比较麻烦,费时费力,意义不是很大。设计的进程模型跟nginx类似,更像是nginx的简化版本。 进程信号量设计信号量是进程间通讯的一种方式,比较简单,单功能也比较弱,只能发送信号给进程,进程根据信号做出不同的处理。 master进程启动的时候保存pid到文件 SIGINT => 平滑退出,处理完正在处理的数据再退出 SIGTERM => 暴力退出,无论进程是否正在处理数据直接退出 SIGUSR1 => 查看进程状态,查看进程占用内存,运行时间等信息 master进程通过信号和worker进程通讯,worker进程安装了2个信号,如下所示: SIGINT => 平滑退出 SIGUSR1 => 查看worker进程自身状态 为什么worker进程只安装2个信号呢,少了个 worker进程是通过master进程fork出来的,这样master进程可以通过 master进程也通过 PHP中有2种信号触发的方式,第一种方式是 第二种是通过 PHP安装修信号量PHP通过 bool pcntl_signal ( int $signo , [callback $handler [, bool $restart_syscalls = true ] ) 第三个参数 <?php
$i = 0;
while ($i<5) {
$pid = pcntl_fork();
$random = rand(10, 50);
if ($pid == 0) {
sleep($random);
exit();
}
echo "child {$pid} sleep {$random}\n";
$i++;
}
pcntl_signal(SIGINT, function($signo) {
echo "Ctrl + C\n";
});
while (1) {
$pid = pcntl_wait($status);
var_dump($pid);
pcntl_signal_dispatch();
}运行之后,我们对父进程发送 child 29643 sleep 48 child 29644 sleep 24 child 29645 sleep 37 child 29646 sleep 20 child 29647 sleep 31 int(29643) Ctrl + C Ctrl + C Ctrl + C Ctrl + C int(29646) 这是运行脚本之后马上给父进程发送了四次 但当把安装信号的第三个参数设置为 pcntl_signal(SIGINT, function($signo) {
echo "Ctrl + C\n";
}, false);这时候给父进程发送 所以第三个参数大概意思就是,是否重新注册此信号,如果为false只注册一次,触发之后就返回, 信号量和系统调用信号量会打断系统调用,让系统调用立刻返回,比如 <?php
pcntl_signal(SIGINT, function($signo) {
echo "Ctrl + C\n";
}, false);
while (true) {
pcntl_signal_dispatch();
echo "123\n";
$limit = sleep(2);
echo "limit sleep [{$limit}] s\n";
}运行之后,按 123 ^Climit sleep [1] s Ctrl + C 123 limit sleep [0] s 123 ^Climit sleep [1] s Ctrl + C 123 ^Climit sleep [2] s daemon(守护)进程这种进程一般设计为daemon进程,不受终端控制,不与终端交互,长时间运行在后台,而对于一个进程,我们可以通过下面几个步骤把他升级为一个标准的daemon进程: protected function daemonize()
{
$pid = pcntl_fork();
if (-1 == $pid) {
throw new Exception("fork进程失败");
} elseif ($pid != 0) {
exit(0);
}
if (-1 == posix_setsid()) {
throw new Exception("新建立session会话失败");
}
$pid = pcntl_fork();
if (-1 == $pid) {
throw new Exception("fork进程失败");
} else if($pid != 0) {
exit(0);
}
umask(0);
chdir("/");
}拢共分五步:
第2步是为第1步做准备,设置进程为会话组长,必要条件是进程非进程组长,因此做第一次fork,进程组长(父进程)退出,子进程通过 第3步是为了不让进程重新控制终端,因为一个进程控制一个终端的必要条件是会话组长(pid=sid)。 第4步是为了恢复默认的文件掩码,避免之前做的操作对文件掩码做了设置,带来不必要的麻烦。关于文件掩码, linux中,文件掩码在创建文件、文件夹的时候会用到,文件的默认权限为666,文件夹为777,创建文件(夹)的时候会用默认值减去掩码的值作为创建文件(夹)的最终值,比如掩码
第5步是切换了当前目录到根目录 对应5步,每一步的各种id变化信息:
另外,会话、进程组、进程的关系如下图所示,这张图有助于更好的理解。 至此,你也可以轻松地造出一个daemon进程了。 命令设计我准备给这个类库设计6个命令,如下所示:
启动命令启动命令就是默认的流程,按照默认流程走就是启动命令,启动命令会检测pid文件中是否已经有pid,pid对应的进程是否健康,是否需要重新启动。 强制停止命令管理员通过入口文件结合pid给master进程发送 强制重启命令
平滑停止命令平滑停止命令,管理员给master进程发送 平滑重启命令
查看进程状态查看进程状态这个借鉴了workerman的思路,管理员给master进程发送 ?/dir /usr/local/bin/php DaemonMcn.php status Daemon [DaemonMcn] 信息: -------------------------------- master进程状态 -------------------------------- pid 占用内存 处理次数 开始时间 运行时间 16343 0.75M -- 2018-05-15 09:42:45 0 天 0 时 3 分 12 slaver -------------------------------- slaver进程状态 -------------------------------- 任务task-mcq: 16345 0.75M 236 2018-05-15 09:42:45 0 天 0 时 3 分 16346 0.75M 236 2018-05-15 09:42:45 0 天 0 时 3 分 -------------------------------------------------------------------------------- 任务test-mcq: 16348 0.75M 49 2018-05-15 09:42:45 0 天 0 时 3 分 16350 0.75M 49 2018-05-15 09:42:45 0 天 0 时 3 分 16358 0.75M 49 2018-05-15 09:42:45 0 天 0 时 3 分 16449 0.75M 1 2018-05-15 09:46:40 0 天 0 时 0 分 -------------------------------------------------------------------------------- 等待worker进程将进程信息写入文件的时候,这个地方用了个比较trick的方法,每个worker进程输出一行信息,统计文件的行数,达到worker进程的行数之后表示所有worker进程都将信息写入完毕,否则,每个1s检测一次。 其他设计另外还加了两个比较实用的功能,一个是worker进程运行时间限制,一个是worker进程循环处理次数限制,防止长时间循环进程出现内存溢出等意外情况。时间默认是1小时,运行次数默认是10w次。 除此之外,也可以支持多任务,每个任务几个进程独立开,统一由master进程管理。 代码已经放到github中,有兴趣的可以试试,不支持windows哦,有什么错误还望指出来。 更多编程相关知识,请访问:编程入门!! 以上就是浅谈PHP中的多进程消费队列的详细内容,更多请关注模板之家(www.mb5.com.cn)其它相关文章! |
