近期接手一項任務:需對 2000 萬用戶名單進行手機號、郵箱綁定狀態檢測。用戶名單易於獲取,但檢測必須逐個調用外部安全接口,接口響應極慢,單線程處理 2000 萬條記錄至少需數天。若 PHP 腳本中途掛掉,進度將難以恢復,因此必須建立可靠的守護機制。
users,字段包含帳號、手機標記、郵箱標記、處理標記(flag)。flag=0 的 500 條記錄,調用接口檢測,生成批量 UPDATE SQL 寫回,並將 flag 置 1。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='名單表';
nums != 500) { $flag = false; }
if ($this->total_nums >= 10000) { exit(0); } // 每 1 萬條退出,由守護進程重啟
$this->getUsers();
$this->checkUserInfo();
$this->updateUserInfo();
sleep(1); // 保護下游接口
}
}
}
$user = new Users();
$user->run();
關鍵點:引入 $total_nums 計數器,每處理 1 萬條主動 exit(0),避免長連接導致的資源洩漏或 DB 連接斷開而腳本卡死無法退出。
#!/bin/bash
PHP_SCRIPT="/path/to/check_users.php"
MAX_RUNTIME=300 # 5 分鐘超時
# 檢查進程是否存在
pid=$(pgrep -f "check_users.php")
if [ -n "$pid" ]; then
# 計算已運行時間
start_time=$(ps -o lstart= -p "$pid" | xargs -I {} date -d "{}" +%s)
now=$(date +%s)
if [ $((now - start_time)) -gt $MAX_RUNTIME ]; then
kill -9 "$pid"
php "$PHP_SCRIPT" &
fi
else
php "$PHP_SCRIPT" &
fi
將此腳本加入 crontab -e,設置 * * * * * /path/to/check_daemon.sh 每分鐘執行。
處理前:testalexlee,0,0,0
處理後:testalexlee,1,0,1(flag=1 表示已完成,has_phone=1 表示綁定手機)
LOAD DATA + Shell 處理可將耗時從天級降至小時級。sleep(1) 避免觸發限流。此方案在受限環境下(無法直連 DB、只能走慢速接口)以最小改動實現了百萬級任務的可靠跑批,核心思想是「分批處理 + 主動退出 + 外部守護」三位一體,適用於各類長耗時、不可中斷的 PHP 異步任務。