shell脚本作为保证PHP脚本不挂掉的守护进程实例分享


Posted in PHP onJuly 15, 2013

前几天开始跑一份数据名单,名单需要提供用户名、是否有手机号、是否有邮箱,用户名单我轻易的获取到了,但是,用户名单有2000w之多,并且去检测用户是否有手机号、是否有邮箱必须得通过一个对外开放的安全接口一个一个用户去请求,然后分析返回值才能知道。

下面是我处理的方案:
1、将2000w名单保存到临时数据表
2、用PHP程序每次从该表获取500个用户,检测完后生成SQL update原纪录
3、为了防止PHP程序突然断掉,用shell脚本每隔1分钟检测,PHP挂掉了则重启
我使用shell脚本作为守护进程的原因是,手机与邮箱的检测接口速度慢,不可能在1~2天将2000w用户检测完。

方案详细:
1、临时保存用户名单表users,表结构如下:

CREATE TABLE `users` ( 
  `account` varchar(50) COMMENT '用户名', 
  `has_phone` tinyint(3) unsigned NOT NULL default '0' COMMENT '是否有手机号', 
  `has_email` tinyint(3) unsigned NOT NULL default '0' COMMENT '是否有邮箱', 
  `flag` tinyint(3) unsigned  NOT NULL default '0' COMMENT '标志位', 
  PRIMARY KEY  (`account`), 
  KEY `flag` (`flag`) 
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8 COMMENT='名单表';

我先将2000多w用户名导入到这个临时表,has_phone与has_email这二个字段默认都是0(没有),标志位flag说明该用户是否已经检测完。
下面是一部分表数据:
9873aaa,0,0,0
adddwwwd876222,0,0,0
testalexlee,0,0,0
codejia.net,0,0,0
haohdouywaa21,0,0,0
 
2、PHP脚本check_users.php
将 用户名单导入到表之后,再写一个简单的PHP脚本,思路是这样的:每次循环从表取flag=0的500个用户,然后请求接口判断用户是否有手机号、邮箱, 生成一条SQL,保存到一个SQLS数组里,等500个用户全部检测完了之后,循环SQLS数组,更新表里这500个名单,并将flag标志位设置为1, 表示已经检测完,下次就不获取了。
由于PHP脚本代码较长,这里分享下简单的代码说明:
<?php 
class Users{ 
    private $data; 
    private $sqls; 
    private $nums;         //判断是否有500用户 
    private $total_nums;   //当前已经检测完的用户数量     //每次取500个用户 
    private function getUsers(){...} 
    //检测这500个用户并生成SQL 
    private function checkUserInfo(){...} 
    //更新这500个用户 
    private function updateUserInfo(){...} 
    //运行 
    public function run(){ 
        $flag = true; 
        while($flag){ 
             if($this->nums != 500){ $flag = false; } 
             if($this->total_nums == 10000){  
                exit(0); //跑完1w个用户就退出,由守护进程启动 
             } 
             $this->getUsers(); 
             $this->checkUserInfo(); 
             $this->updateUserInfo(); 
             sleep(1); //跑完500用户休息1秒,保护用户检测接口      
         } 
    } 
} 
$user = new Users(); 
$user->run(); 
?>

上面是简洁版的PHP脚本,大概意思到了,刚开始的版本是没有$total_nums这个变量,是因为刚开始跑这个脚本的时候,发现只跑完了4w多条脚本就挂球了,后来一看,是因为连接数据库没连上,脚本一直挂在那里。加上这个变量也无法解决这个问题,只是在每次跑完1w个用户之后,PHP脚本退出,再由下面的shell脚本重新启动。

3、shell脚本作为守护进程
我把这个shell脚本加到了crontab里边,每隔1分钟执行一次,这个shell脚本很简单,检测check_users.php是否存在进程id,如果存在,则说明PHP脚本还在运行,shell脚本不做任何操作;如果不存在,则说明PHP脚本已经exit(0)跑完了1w用户退出了,那么shell脚本启动该脚本,进入下一个1w用户名单的检测。
上面我有讲到,如果PHP脚本在连接数据库的时候,无法连接上的时候,PHP会一直挂球在那里,无法退出了。我在shell脚本里加了一个时间检测,当PHP脚本进程存在的时候,计算已经存在了多长时间,如果超过了我预想的时间,则将PHP脚本kill掉,再重启。

开头的举例数据,结果类似如下:
testalexlee,1,0,1
codejia.net,0,0,1
haohdouywaa21,1,1,1
9873aaa,0,1,1
adddwwwd876222,1,0,1

说在最后:以上用户名单数据只是举个栗子,不要太认真,2000w数据,我估计要跑一段时间了,因为检测接口比较慢,接口在接到请求后还要连表,查表,再返回。其实,最好的方法还是直接从接口请求的表拉一份名单出来,再用shell命令处理下很快就有结果了,可是在公司就是这样,有些东西不开放的,你懂的~~~

PHP 相关文章推荐
PHP Session_Regenerate_ID函数双释放内存破坏漏洞
Jan 27 PHP
33道php常见面试题及答案
Jul 06 PHP
php实现可运算的验证码
Nov 10 PHP
学习php设计模式 php实现备忘录模式(Memento)
Dec 09 PHP
PHP合并数组的2种方法小结
Nov 24 PHP
老生常谈PHP 文件写入和读取(必看篇)
May 22 PHP
PHP在同一域名下两个不同的项目做独立登录机制详解
Sep 22 PHP
PHP常见的几种攻击方式实例小结
Apr 29 PHP
解决Laravel 使用insert插入数据,字段created_at为0000的问题
Oct 11 PHP
laravel 之 Eloquent 模型修改器和序列化示例
Oct 17 PHP
使用laravel指定日志文件记录任意日志
Oct 17 PHP
YII2框架使用控制台命令的方法分析
Mar 18 PHP
PHP 伪静态技术原理以及突破原理实现介绍
Jul 12 #PHP
php的$_FILES的临时储存文件与回收机制实测过程
Jul 12 #PHP
php图像处理函数大全(推荐收藏)
Jul 11 #PHP
PHP 获取远程文件大小的3种解决方法
Jul 11 #PHP
深入Nginx + PHP 缓存详解
Jul 11 #PHP
基于PHP中的常用函数回顾
Jul 11 #PHP
PHP 获取文件权限函数介绍
Jul 11 #PHP
You might like
常用的php ADODB使用方法集锦
2008/03/25 PHP
Zend Framework入门教程之Zend_Db数据库操作详解
2016/12/08 PHP
PHP中abstract(抽象)、final(最终)和static(静态)原理与用法详解
2020/06/05 PHP
标题过长使用javascript按字节截取字符串
2014/04/24 Javascript
基于jQuery实现的图片切换焦点图整理
2014/12/07 Javascript
JS针对浏览器窗口关闭事件的监听方法集锦
2016/06/24 Javascript
NodeJs——入门必看攻略
2016/06/27 NodeJs
关于js原型的面试题讲解
2016/09/25 Javascript
URL的参数中有加号传值变为空格的问题(URL特殊字符)
2016/11/04 Javascript
Html5 js实现手风琴效果
2020/04/17 Javascript
正则表达式基本语法及表单验证操作详解【基于JS】
2017/04/07 Javascript
微信小程序开发之从相册获取图片 使用相机拍照 本地图片上传
2017/04/18 Javascript
JQueryMiniUI按照时间进行查询的实现方法
2017/06/07 jQuery
React Native自定义控件底部抽屉菜单的示例
2018/02/08 Javascript
解决axios post 后端无法接收数据的问题
2019/10/29 Javascript
在react-antd中弹出层form内容传递给父组件的操作
2020/10/24 Javascript
ReactRouter的实现方法
2021/01/25 Javascript
[04:01]2014DOTA2国际邀请赛 TITAN告别Ohaiyo期望明年再战
2014/07/15 DOTA
[59:30]VG vs LGD 2019国际邀请赛淘汰赛 胜者组 BO3 第二场 8.22
2019/09/05 DOTA
Python实现读取txt文件并画三维图简单代码示例
2017/12/09 Python
解决python写入带有中文的字符到文件错误的问题
2019/01/31 Python
总结Python图形用户界面和游戏开发知识点
2019/05/22 Python
Python 读取串口数据,动态绘图的示例
2019/07/02 Python
解决os.path.isdir() 判断文件夹却返回false的问题
2019/11/29 Python
python实现局域网内实时通信代码
2019/12/22 Python
PyCharm第一次安装及使用教程
2020/01/08 Python
Python netmiko模块的使用
2020/02/14 Python
HolidayLettings英国:预订最好的度假公寓、别墅和自助式住宿
2019/08/27 全球购物
如何写一份好的自荐信
2014/01/02 职场文书
优秀应届毕业生推荐信
2014/02/18 职场文书
电子商务助理求职自荐信
2014/04/10 职场文书
房地产公司工程部经理岗位职责
2015/04/09 职场文书
四十年同学聚会致辞
2015/07/28 职场文书
2019年世界儿童日宣传标语
2019/11/22 职场文书
解析Java异步之call future
2021/06/14 Java/Android
漫画「日和酱的要求是绝对的」第3卷封面公开
2022/03/21 日漫