如何管理php常驻进程,一看就懂系列之 如何实现与控制php常驻进程-Go语言中文社区...

前言

关于如何实现与控制php常驻进程,不管是google还是baidu上进行搜索,都没有感觉看起来赏心悦目的解答,于是决定自己动手总结下。

有同学会问了,整这个干甚?简单的说就是,可以让一个php脚本一直处于运行的状态。从而实现将项目中某些耗时操作异步化,进队列后由php脚本取出再执行。

有同学又会问了,直接在服务器直接命令“php test.php &”,不就可以实现了?那么这样做的话有三点还需要考虑:1.如何保证此进程的稳定性(挂了怎么办)2.如果想开10个进程,手动去执行10回好像不怎么友好。3.关闭的话需要手动杀死进程?

有同学又会问了,这个不是在crontab加一个定时任务从而一直去执行不就好了,而且保证了稳定性。准确地说这也是可以的,但是有三点需要考虑:1.每回新增队列都要加一回crontab真的好吗。2.还是开10的进程问题(同上)。3.那要是关闭的话还要去备注crontab任务?

所以本文所设计的方案主要解决以下几个问题:

1.如果实现php的常驻?(不依赖第三方php扩展)

2.如何保证进程的稳定性(谁来守护的问题)?

3.如何方便的管理php进程的关闭与重启?

4.如何方便的管理php进程的并发数?

5.如何进行对php进程的监控?

正文

demo文件描述

eb93fc592b18fa0f6556bfb14896ad24.png

cron_demo

1.cron_watchdog.sh:用于添加以及调起php进程

2.cron_watchdogd.sh:用于监控cron_watchdog.sh,保证其一直在运行

3.cron_zombie_alert.sh:用于进程文件的扫描监控,与错误通知。

privdata/cron_demo

cron_count.ini:用于控制php进程的并发数

cron_switch.ini:用于控制php进程的开关

cron_status/ :用于存在标记php进程的pid,以供cron_zombie_alert.sh扫描

cron_kill.log:用于记录cron_zombie_alert.sh扫描到并且kill的僵尸进程。

由于是一看就懂系列,故具体文件解析会附带上详细的解读。

cron_watchdog.sh的实现与解读

代码实现

#!/bin/bash

#该脚本需在bash版本>=4中执行

#输出当前地址

CRON_DIR=$(cd $(dirname "$0"); pwd)

#执行进程监控脚本的命令

zombie_alert_cmd="/bin/sh $CRON_DIR/cron_zombie_alert.sh& > /dev/null"

#获取php进程并发数配置

CRON_COUNT_INI=/www/privdata/cron_demo/config/cron_count.ini

echo $CRON_COUNT_INI

#此类写法需要bash版本>4的支持。(如果mac默认3.x,所以不支持)

declare -A deamon_map

#key 为cron_count里的key value为命令脚本地址

deamon_map["test"]="$CRON_DIR/test.php"

while true; do

#循环执行deamon_map里的命令

for deamon_count_key in "${!deamon_map[@]}" ; do

echo $deamon_count_key

#计算出配置文件里面php进程的并发数

SUM=`grep "^$deamon_count_key *=" "$CRON_COUNT_INI" | awk '{print $3}'`

#若在cron_count.ini中不存在,则默认赋值队列并发数1

if ! (echo $SUM | egrep -q '^[0-9]+$'); then

SUM=1

fi

php_script="${deamon_map["$deamon_count_key"]}"

#计算当前运行中的php进程数目

proc=`/bin/ps xaww | grep -v " grep" | grep "$php_script" |wc -l`

current_count=$proc

#若小于进程的配置数,则进行调起

if [ $current_count -lt "$SUM" ];then

need_to_open_count=`expr $SUM - $current_count`

while [ $need_to_open_count -gt 0 ]

do

php "$php_script" &

(( need_to_open_count-- ))

done

fi

done

#php进程的监控与消息通知

eval "$zombie_alert_cmd"

sleep 1

done

shell关键点解读

1.ps xaww:

a 显示终端上地所有进程,包括其他用户地进程

x 显示没有控制终端地进程

ww 避免详细参数被截断;

2.${!arr[@]} 用于返回数组array的所有下标

3.deamon_map[“test”]=”$CRON_DIR/test.php”

用于添加cron任务,test为脚本在cron_count.ini里面的标号(这里设置为php脚本文件名),test.php为所需要执行的php脚本。

解决问题

1.进程添加问题,只需在此处添加一行配置即可。

2.进程并发管理问题,只需在cron_count.ini配置即可。

cron_watchdogd.sh的实现与解读

代码实现

#!/bin/sh

CRON_DIR=$(cd $(dirname "$0"); pwd)

cmd="/bin/sh $CRON_DIR/cron_watchdog.sh& > /dev/null"

#检测cron_watchdog.sh是否在执行

proc=`/bin/ps xaww | grep -v " grep" | grep -- "cron_watchdog.sh"`

#根据返回结果进行判断脚本是否执行

if test -z "$proc"

then

#若不执行,那么就调起命令执行

eval "$cmd"

fi

此外需要在/etc/crontab中添加以下命令,以保证此脚本定时都会去检测一回。

*/1 * * * * root sh /www/cron_demo/cron_watchdogd.sh > /dev/null 2>&1

shell关键点解读

1.grep -v:逆向输出. 打印不匹配模式的行

2.test –z 字符串:测试字符串的长度是否为零

3.eval

此命令会执行两回后续的语句,在这里,第一回先翻译"$cmd"成"/bin/sh $CRON_DIR/cron_watchdog.sh& > /dev/null",第二回在进行执行这个命令

解决问题

1.cron_watchdog.sh脚本的监控,保证其不死掉

cron_zombie_alert.sh的实现与解读

代码实现

#!/bin/sh

PID_LOG=/www/privdata/cron_demo/cron_status/

KILL_LOG=/www/privdata/cron_demo/log/cron_kill.log

#用于检测30分钟未进行更新的进程文件。

Minute=30

#PID_LOG

cd "$PID_LOG"

if [ "$?" == 0 ];then

#若进程文件30分钟没进行更新则认为已经僵死,需要kill并报警

for pid in `find ./ -mmin +"$Minute"| grep -v /$ | awk -F '/' '{print $2}'`

do

if [ "$pid" != '' ];then

NOW=`date +%Y-%m-%d_%H:%M`

HOSTNAME=`hostname`

nl='

'

PROCESS=`ps p$pid fuh`

if [ "$PROCESS" != '' ];then

PSTACK=`pstack $pid`

#将pid进程信息输出到tmp.out文件,若2秒之后还在运行再kill此进程

TMP=`timeout 2 strace -p $pid -o tmp.out`

STRACE=`cat tmp.out`

rm tmp.out

fi

#组织报警消息

message="$NOW $HOSTNAME zombie process id $pid $nl$PROCESS$nl$PSTACK$nl$STRACE--"

echo "$message">>"$KILL_LOG"

#kill "$pid"

cd "$PID_LOG"

#同时删除进程文件

rm -r "$pid"

#进行邮件或者其他的形式将message的内容同步出去

fi

done

fi

shell关键点解读

1.timeout:

timeout [选项] 数字[后缀] 命令 [参数]...

或:timeout [选项]

运行指定命令,如果在指定时间后仍在运行则杀死该进程。

后缀"s"代表秒(默认值),"m"代表分,"h"代表小时,"d"代表天。

2.strace:

-f :除了跟踪当前进程外,还跟踪其子进程。

-o file :将输出信息写到文件file中,而不是显示到标准错误输出(stderr)。

-p pid :绑定到一个由pid对应的正在运行的进程。此参数常用来调试后台进程。

解决问题

1.cron_status底下进程文件的管理。

2.处理php进程僵死的情况。发出相应报警信息。

简单的例子

用于测试的php脚本片段。主要实现功能:每隔10秒输出数字到tset_cron.log日志。

define('ROOT_PATH', dirname(__FILE__));

//一些初始化操作,常量定义以及公共函数的引入

include(ROOT_PATH . '/cron_init.php');

$log_file = LOG_DIR . '/test_cron.log';

//获取进程pid

$pid_status_log = CRON_STATUS_DIR . '/' . getmypid();

$i = 0;

while (true) {

// 将其放入cron_status中以供检测

file_put_contents($pid_status_log, 1);

//从cron_switch.ini中来判断此进程是否开启,这个函数后面会单独解析

$cron_flag = cron_switch(TEST_CRON_KEY);

//若关闭则删掉进程文件

if (!$cron_flag) {

unlink($pid_status_log);

exit();

}

// 可从队列中取出数据进行处理

// 这里作为例子,以记录一个日志好了

$msg = $i ."n";

file_put_contents($log_file, $msg, FILE_APPEND);

sleep(10);

$i++;

}

cron_switch函数

function cron_switch($task = 'all') {

//解析cron_switch.ini文件

$cron_switch = parse_ini_file(CRON_SWITCH_FILE);

if ($task == 'all') {

return $cron_switch;

} else {

$task = str_replace(KEY_PREFIX, '', $task);

$current_cron_switch = $cron_switch [$task];

//第二个判断用于重启进程之用。只要将cron_switch的数字设置大一点则认为重启,设置为0代表关闭,1代表开启。

if($GLOBALS['current_cron_switch'] && $GLOBALS['current_cron_switch']

//若小于当前配置文件

$current_cron_switch = 0;

}

if($current_cron_switch){

//全局标记当前的cron_switch值,用于当作重启的标志

$GLOBALS['current_cron_switch'] = $current_cron_switch;

}

return $current_cron_switch;

}

}

开始运行啦

加好定时任务后发现:

b13c775334d7cf73017cefc244bcb68a.png

日志每隔10s输出一个数字了。此时将此php进程kill掉,马上发现,有重现开始跑了。

f3225f905f3b8d94b9a110eaeff2c555.png

此时:

3941d64a095c604676fff043ac8282d2.png

现在试试进程数设置为2(cron_count.ini设置“test = 2”),会发现以上命令后,进程数会变为2个。(这里不截图了,因为很晚了)

代码demo

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值