ブログに戻る

大規模データ収集の安定性:スケール拡大後に初めて表面化する問題

10件では安定していた収集処理も、数千件に拡大すると信頼性が落ちることがあります。失敗の分類と重複排除、レート制限と並行実行、再開、ネットワーク出口の障害、整合性検証、主要な監視指標は、大規模化して初めて重要になります。

データ収集スクリプトは10件の対象では順調に動いていても、数千件へ拡大すると成功率が落ち始めることがあります。リトライを追加し、プロキシを変更し、並行数を調整しても、問題が繰り返し発生します。詳しく調べると、詰まっているのはパース処理そのものではなく、整備されていない複数のエンジニアリング層であることが少なくありません。小規模では、こうした問題自体が現れないことがあります。

まず失敗を分類してからリトライする

データ収集では失敗は避けられません。重要なのは種類を分けることです。ネットワークの揺らぎや接続リセットはすぐに再試行できます。一時的なレート制限にはバックオフ後に再試行します。ページ構造の変更でパース結果が空になる場合、1万回リトライしても解決しないため、記録してアラートを出すべきです。対象自体が存在しないなら完了扱いにします。環境やネットワーク出口が起動できない場合は別のものへ切り替えて再試行します。

何でも一律にリトライするのは、最も起こりやすい失敗の一つです。人の対応が必要な問題をループの中に隠し、同時にクォータや出口リソースを無駄に消費します。バックオフも必要です。再試行間隔を徐々に広げないと、同じ時間帯に大量のタスクが一斉に戻り、かえってレート制限を強めます。

リトライの次に必要になるのが重複排除です。再試行によって同じタスクが複数回実行される可能性があるため、各タスクには安定した一意の識別子が必要です。例えばURLを正規化した後の値を使い、その識別子に基づいてデータベース書き込みを冪等にします。そうしなければ、リトライが増えるほど汚れたデータも増えます。

レート制限と並行実行は別の問題

並行数を増やしても、必ずしもスループットが上がるわけではありません。同時に3つの制約が働きます。対象サイトがどこまで耐えられるか、超えた場合にレート制限で全体スループットが下がること、ローカル環境のメモリとCPU、そして1つの環境やセッションで複数タスクを同時実行できるかどうかです。

安定した進め方は、低い並行数から始めて徐々に負荷を上げ、成功率と応答時間を同時に可視化して、明確に悪化する転換点を見つけることです。レート制限は別の概念で、同じ対象へのアクセス頻度を制御するものであり、全体の並行数とは同じではありません。1つのバッチが複数サイトに分散する場合、サイトごとに別々のペースを設定する必要があります。

再開には状態の永続化が必要

数時間動くタスクが途中で止まることは珍しくありません。最初からやり直すコストは大きすぎます。そのため、未処理、処理中、完了という状態に加え、リトライ回数、次回実行可能時刻、エラー種別を永続化する必要があります。プロセス起動時には、メモリから作り直すのではなく、ストレージからキューを復元します。

キューをメモリだけで管理する方式は、動いているように見える典型例です。プロセスが落ちると、待機中のタスクがすべて失われ、件数も合わなくなります。

プロキシとネットワーク出口の障害は分けて扱う

対象に出口をブロックされる、プロキシが落ちる、地域ノードの状態がずれる、といったことは大規模化すると継続的に起こります。例外ではなく通常状態です。出口は交換可能なリソースとして扱います。タスク失敗時には、対象側のレート制限なのか出口が利用不能なのかを先に判断し、前者ならバックオフ、後者なら出口を切り替えて再試行します。各出口の失敗率も記録し、明らかに悪化したグループは外します。

逆に、すべてのタスクが1つの出口を共有すると、1つのタスクが経路を壊しただけで後続すべてに影響します。調査ではログをさかのぼり、どのタスクが原因だったかを特定する必要があります。

データ整合性を検証する

処理が完了したからといって、データが正しいとは限りません。保存後に、完了タスク数と保存行数が一致するか、パース結果が空の割合はどれくらいか、重要フィールドの欠損率が異常に上がっていないか、重複行がいくつあるかを確認できる必要があります。

こうした検証を複雑にする必要はありません。バッチごとのサンプリングでも十分ですが、誰かが結果を見る必要があります。規模が大きくなると、誤ったデータはデータがないことより厄介です。

監視すべき指標

指標を増やしすぎる必要はありません。システムの健全性を示すものをいくつか見れば十分です。

  • 成功率と失敗種別の分布。どのエラーが増えているかを見る
  • タスクキューの長さと平均待ち時間。滞留が伸び続ける場合、投入量と処理能力が合っていない
  • アクティブな環境数と関連プロセス数。長時間一方向に増え続ける場合、リソース回収の漏れを疑う
  • 単位時間あたりの出力量。レート制限でスループットが抑えられていないかを見る
  • ネットワーク出口の失敗率。ノード群を交換すべきか判断する

これらの指標のうち1つでも長時間一方向に変化し続けるなら、まずリソース回収とリトライのロジックを確認します。

環境レイヤーを独立させる

これらをまとめて考えると、同じ結論になります。環境レイヤーはスクリプトから独立して管理すべきです。環境のプール化には、各スクリプトに環境を分散させるのではなく集中してスケジュールできることが必要です。リソース回収には、各スクリプトの自己復旧に頼らず状態を照会できることが必要です。別環境や別出口へ切り替えて再試行する仕組みも、環境を独立してスケジュールできて初めて成立します。

スクリプトはロジックを担当し、環境レイヤーはリソースと識別情報を担当します。この種のアーキテクチャでPurpleMarkが担うのはこのレイヤーであり、まとめて作成でき、独立したネットワーク出口に紐づけられ、状態を照会できる環境リソースを提供します。

コンプライアンス上の境界

大規模化できるからといって、自由にデータを収集してよいわけではありません。対象サイトのrobotsルールと利用規約を守り、個人情報を収集せず、技術的な保護措置を回避せず、相手の通常サービスに影響しないようリクエスト頻度を制御します。安定性は技術上の問題であり、収集してよいかどうかは別の問題です。両方を満たす必要があります。