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