採集任務從十個目標擴到上千個,先出問題的通常不是解析邏輯。失敗分類與去重、限速與並行、斷點續跑、出口失效處理、一致性校驗,以及幾個關鍵監控指標,都是規模化之後才真正重要的工程問題。
一個採集腳本在十個目標上跑得順,擴到上千個就可能開始掉成功率。加過重試、換過代理、調過並行,問題還是反覆出現。往下查,卡住的往往不是解析邏輯,而是幾層尚未搭好的工程能力。這些事情在小規模時可能根本不會出現。
先分類失敗,重試才有意義
採集一定會有失敗。關鍵在於是否把失敗分型:網路抖動和連線重設可以立刻重試;臨時限流要退避之後再重試;頁面結構變化導致解析結果為空時,重試一萬次也沒有用,應該記錄並告警;目標本來就不存在,標記完成即可;環境或網路出口啟動不了,就換一個再試。
一律重試是最容易犯的錯。它會把需要人工介入的問題藏在迴圈裡,同時白白消耗配額和出口資源。退避也要做,重試間隔應逐步增加,否則一批任務會在同一個時間窗口集中打回去,反而讓限流更嚴重。
重試再往下一層就牽涉到去重。一次任務可能因為重試而執行多遍,所以每個任務都要有穩定的唯一識別——例如 URL 正規化之後的值——寫入資料庫時依這個識別做冪等寫入。否則重試越多,髒資料越多。
限速和並行是兩件事
提高並行數,吞吐量不一定跟著上升。同時有三個限制在起作用:目標網站能承受多少負載,超過後會觸發限流並讓總吞吐下降;本機的記憶體與 CPU;以及單一環境或工作階段能不能同時跑多個任務。
比較穩定的做法是從低並行開始逐步加壓,把成功率和回應時間一起觀察,找出明顯變差的轉折點。限速是另一件事,它控制的是對同一個目標的存取節奏,和全域並行數不是同一個概念。一批任務分散到多個網站時,每個網站都要分別設定節奏。
斷點續跑依賴狀態持久化
任務跑幾個小時中斷一次很正常,從頭再跑的成本通常難以接受。前提是狀態要落盤:待處理、處理中、已完成,再加上重試次數、下次可執行時間、錯誤類型。程序啟動時應該從儲存中讀回佇列,而不是從記憶體重新建立。
只在記憶體裡維護佇列,是最常見的「看起來能跑」做法。程序一掛,排隊中的任務全部遺失,帳也對不上。
代理和網路出口失效要分開處理
出口被目標封鎖、代理離線、區域節點漂移,這些情況在規模化之後會持續發生,不是例外而是常態。把出口當成可替換的資源來管理:任務失敗時先判斷是目標限流還是出口不可用,前者退避,後者更換出口後重試;同時記錄每個出口的失敗率,把明顯變差的一批移除。
反過來,如果所有任務共用同一條出口,一個任務把鏈路打壞,後面的任務都會受影響,排查時還得從日誌往回推是哪一個任務造成的。
資料一致性校驗
跑通不等於資料正確。寫入之後要能回答幾個問題:任務完成數和寫入列數能不能對上、解析結果為空的比例是多少、關鍵欄位的缺失率有沒有異常上升、重複列有多少。
這類校驗不用做得很複雜,按批次抽查即可,但一定要有人看結果。規模大了之後,錯誤的資料往往比沒有資料更麻煩。
監控該看哪些指標
指標不必貪多,幾個能反映系統健康狀態的就夠了。
- 成功率,以及失敗類型的分布,用來看哪一類錯誤正在上升
- 任務佇列長度和平均等待時間;積壓持續變長代表入口與處理能力不匹配
- 活躍環境數和相關程序數;長時間單向成長通常代表資源回收有洩漏
- 單位時間產出量,用來判斷吞吐是否被限流壓住
- 出口失敗率,用來決定是否需要更換一批節點
只要其中一個指標長時間單向變化,先查資源回收和重試這兩處邏輯。
環境層要獨立出來
把這些問題放在一起看,會得到同一個結論:環境層必須獨立於腳本管理。環境池化要求環境可以集中排程,而不是散落在各個腳本裡;資源回收要求狀態可以查詢,而不是靠腳本自己兜底;換環境重試、換出口重試這些動作,也只有在環境能夠獨立排程時才成立。
腳本只管邏輯,環境層管理資源與身分。PurpleMark 在這類架構裡承擔的就是這一層,提供可批次建立、可綁定獨立網路出口、狀態可查詢的環境資源。
合規邊界
規模化能力不等於可以隨意採集。應遵守目標網站的 robots 規則和服務條款,不採集個人資訊,不繞過技術保護措施,並控制請求頻率,不要影響對方服務的正常運作。穩定性是技術問題,能不能採集是另一個問題,兩邊都必須符合要求。


