前幾天開始跑一份數據名單,名單需要提供用戶名、是否有手機號、是否有郵箱,用戶名單我輕易的獲取到了,但是,用戶名單有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命令處理下很快就有結果了,可是在公司就是這樣,有些東西不開放的,你懂的~~~