24時間で420万件のリクエスト。平均応答時間は774ms。成功率は99.91%。再構築前の7日間、同じワークロードの平均応答時間は2.5秒だった。同じハードウェア、同じターゲットサイト、同じプロキシプールを使用しながら、平均応答時間が70%低下したことになる。我々は、顧客の時間を静かに奪っていたリクエストパスの一部を再構築した。
本稿では、何が変更されたか、実際の数値はどうなっているか、そしてSingleとProxy Finderの違いとその理由について解説する。
最初にデータについての注意点。この記事の数値は本番トラフィックからのものだが、1つの特定のターゲットホストを除外している。このホストは今週ずっと積極的にレート制限とリクエストに対するチャレンジを行っており、すべての指標を歪めている。これを含めると成功率は約95%に低下する。しかし、この5%の差はインフラの障害ではない。我々のpickerがどれほど優れていても、1つのサイトがリクエストを拒否している結果だ。システムが協力的なターゲットに対して実際にどう動作するかを示すため、このデータは除外した。
What the data shows
過去1週間の本番トラフィック全体での1日あたりの平均は次のとおりである。

4月22日から4月27日: 平均は2,318msから3,116msの間で、トラフィックは1日あたり280万から770万リクエスト。4月25日は770万リクエストで3,116msと突出している。これは土曜日のピークである(週末はボリュームが顕著に増加し、平均を押し上げる)。4月28日: 380万リクエストで672ms。4月29日(UTCの09:00までの部分的なデータ): これまでのところ170万リクエストで880ms。
同じアーキテクチャ。同じプロキシ。同じターゲットサイト。異なるリクエストパス。
パーセンタイルの図は平均よりも明確だ。平均は悪いテールを隠すことができるが、パーセンタイルは隠せない。

チャートは、再構築後の24時間と再構築前の24時間を比較している。p50はほとんど動かなかった(そして4%上昇したが、これは正直なデータだ。高速パスはすでに良好であり、新しいpickerはテールで多くを節約するために、事前の処理に少しだけ労力を費やしている)。この期間の平均は48%低下した。p95は8.5秒から3.9秒になり、54%の削減。p99は20秒から7.8秒になり、61%の削減。ここが苦痛の根源であり、スクレイパーが最も遅い5%のリクエストの返りを待っているときに実際に感じる部分だ。再構築前の7日間(平均が約2.5秒で推移していた期間)と比較して、今日の774msの平均は70%の低下である。
成功率も上昇した。同じ期間で98.85%から99.91%に上昇。Proxy Finderのみでは、率は99.89%に達した。Singleでは99.96%。これは我々が最も誇りに思っている数字だ。再試行することなく、最初の試みで有用なデータを返す頻度を示しているからだ。
Two products, two latency profiles
我々はSingleとProxy Finderを互いに比較しない。これらは異なる問題を解決し、異なるレイテンシ予算を持っている。一方を使用してもう一方の数値を見ているなら、間違ったスコアボードを読んでいることになる。

Single は、我々のインフラを介したワンショットのHTTPリクエストである。URLを渡すと、本番コールの約99%で機能することがすでに分かっているプロキシIDが使われる。そのプロキシ経由でURLを取得し、レスポンスを得る。ローテーションロジックも、再試行カスケードも、プロキシの入れ替わりもない。過去24時間: p50で100ms、p95で371ms、p99で581ms。ほとんどのコールは1/5秒未満で完了する。最悪の1%でさえ600ms未満で返ってくる。
Proxy Finder はディスカバリレイヤーである。パブリックプロキシのプール全体でリクエストをローテーションし、各候補を検証し、失敗時に再試行し、実際に機能した最初のレスポンスと、それを実行したプロキシのIDを返す。p50で445ms、p95で5.4秒、p99で10.2秒。遅いのは、そうである必要があるからだ。要点は、スクレイパーがターゲットサイトにアクセスするIPがローテーションされ、使い捨てであるということだ。ブロックリストやレート制限に対する回復力と引き換えに、数秒のオーバーヘッドを支払っている。
Singleが非常に高速である理由は魔法ではない。SingleはProxy Finderが発見したものを信頼しているからだ。Proxy Finderを一度呼び出して「このプロキシは機能した、これがそのIDだ」と返された場合、Singleを介した同じターゲットへの後続のフェッチは、ディスカバリステップ全体をスキップする。すでに検証に合格したプロキシに直接アクセスするのだ。
How teams use them together
ターゲットに頻繁にアクセスするほとんどのチームは、2ステップのパターンに従う。最初のコールは探索的であり、残りはコミットされる。
最初のコールはProxy Finderに行く。プール内をローテーションし、受け入れルールに対して各候補を検証し、機能したプロキシのIDとともにレスポンスを返す。そのIDは、同じターゲットにアクセスしたい将来のコールのためのハンドルである。
それ以降のすべてのコールは、プロキシIDが付加された状態でSingleに行く。ディスカバリも、検証も、再試行カスケードもない。指定されたプロキシ経由でリクエストをルーティングし、レスポンスをストリーミングして戻す。それがp50で100msに達するパスである。
昨日機能したプロキシが今日ブロックされた場合、1回のコールのためにProxy Finderにフォールバックして再発見し、新しいIDでSingleフェッチを再開する。我々は古さを隠蔽しない。渡されたプロキシIDが死んでいる場合は、ローテーションできるようにすぐに通知する。
99/1の分割(ボリュームではSingleが支配的、ディスカバリではProxy Finderが支配的)が、Singleの数値がそのようになる理由である。Singleが本質的に高速な製品であるというわけではない。Singleは定常状態であり、Proxy Finderはキャリブレーションステップであるということだ。ほとんどのワークロードは大部分が定常状態である。
あなたの仕事が「誰が呼び出しているかを気にしないクリーンなパブリックAPIからこのJSONを取得する」ことである場合、プロキシを完全にスキップしてSingleを単独で使用する。仕事が「フラグを立てられることなく、使い捨てIPのプールからこの保護されたページにアクセスする」ことである場合、それらを組み合わせる。それらは代替品ではない。同じワークフローのステージである。
What we changed
成果の大部分は、プロキシローテーションパスの3つの要素を再構築したことから得られた。どれも新しいアイデアではなく、先送りしていたものだった。
The pool stopped trusting bad data. 再構築前、プロキシディレクトリは必要以上に長くエントリを保持していた。これらのエントリのいくつかは、もう到達できなかった。それらのいずれかを選ぶことは、それを厳しい方法で見つけるために15〜30秒を費やすことを意味した。我々は、プールがほぼリアルタイムで実際に生きているものを反映し、pickerが最近成功したIPを優先するモデルに移行した。
Quality scores per proxy, not just up-or-down. 以前は、応答に5秒かかるプロキシは、どちらも最終的に成功する限り、300msかかるプロキシと同じに見えていた。現在、pickerはレイテンシも追跡する。遅いけれど機能するプロキシはキューの最後に押しやられる。高速なプロキシは、ホットな間に再利用される。これは聞いた以上に重要だ。なぜなら、レイテンシ分布のロングテールは、古いpickerが選び続けていた「遅いけれど機能する」プロキシで構成されているからだ。
Per-target quality scores. あるドメインで信頼できるプロキシが、別のドメインでは不安定になることがある。あるサイトに対してきれいに機能するIPが、別のサイトではブロックされたりレート制限されたりする。我々のpickerは現在、グローバルだけでなく、ターゲットホストごとに成功とレイテンシを追跡している。特定のドメインに対するフェッチを要求すると、そのドメインで最近実際に優れたパフォーマンスを示したプロキシから選択する。グローバルに優れたプロキシも候補に残るが、正確なターゲットで強力な実績を持つプロキシは、全体的に強力な実績を持つプロキシよりも上位にランク付けされる。
Smarter retry escalation. リクエストが失敗したとき、以前はすぐに並行して再試行を展開していた。それは無駄であり、さらに悪いことに、1つの悪いプロキシが連鎖的なフォローアップを引き起こし、それらがすべて順番に失敗する可能性があった。現在、再試行は試行間に短いバックオフを挟んで順次エスカレートする。そのため、失敗は失敗であり、再試行は再試行であって、乗数ではない。
目には見えにくいが、言及する価値のある2つ目のカテゴリの変更がある。
Restart resilience. 以前は、リクエストインフラストラクチャの再デプロイには、プロキシ品質スコアマップをゼロから再構築しなければならない5〜15分のウィンドウが必要だった。そのウィンドウの間、pickerは本質的に推測している状態だった。顧客はこれを、すべてのデプロイ直後のレイテンシスパイクとして見ていた。我々は現在、再起動を越えて品質マップを永続化している。システムはウォーム状態で起動する。今日現在、レイテンシスパイクを発生させることなく、日中にインフラストラクチャの変更をデプロイできるようになった。今朝実行した再起動テストでは、15秒の接続の途切れと、その後のリカバリ時間ゼロが示された。これは、デプロイサイクルにおける静かだが意味のある変更だ。もう、トラフィックを回避して再デプロイをスケジュールする必要はない。
Cleaner failure signals. インフラ内部で何か問題が発生した場合、再試行ロジックは適切なHTTPステータスコードを受け取って対処できるようになった。一時的に利用できないバックエンドは503を返す。不正な形式のJSONを返したバックエンドは502を返す。真の内部エラーは500を返す。以前は、これら3つはすべて500のように見えていたため、再試行ロジックは「待機して再試行」と「これは壊れている、エスカレーションする」を区別できなかった。現在はそれが可能だ。
What this looks like for you
ローテーションされたプロキシに対してスクレイパーを実行している場合、実用的な変更点は、p95とp99が1週間前からそれぞれ約半分になることだ。平均リクエスト時間は短縮される。遅いが最終的に機能するプロキシによる再試行が減少する。1,000リクエストのジョブが20分ではなく1時間かかる原因であるテールレイテンシもそれに伴って低下する。
Singleを実行している場合、pickerの動作が主にテールで成果を上げていることがわかる。p99は600ms未満に低下した。これは、不運な1%のリクエストでもすぐに返ってくることを意味する。Singleはすでに高速だった。現在は一貫性がある。
Honest limitations
我々はすべてを修正したわけではない。引き続き適用されるいくつかの詳細事項:
Proxy Finder p99 is still around 10 seconds. 半分にカットしたが、ロングテールは本物だ。その一部は我々の責任(プールの深さ、まれなターゲットでのpickerのノイズ)だ。しかし多くの部分はそうではない。ターゲットサイト自体が遅い場合や、特定のルートをレート制限する場合、検査に時間がかかるチャレンジページを返す場合、あるいは単にタイムアウトする場合がある。我々のインフラストラクチャは利用可能な最良のIPを選択できるが、応答するかどうかを決定しているターゲットサーバーを高速化することはできない。ジョブが5秒以内にすべてのリクエストを返すことに依存している場合は、許容値に一致するリクエストごとのタイムアウトを設定し、再試行レイヤーを信頼してほしい。
Some targets are hostile, and that shows up in your numbers. 冒頭で述べたように、99.91%の成功率には、今週積極的にチャレンジを行っている1つのホストは含まれていない。それを含めると、成功率は約95%に低下する。そのホストはユニークではない。パブリックウェブデータを扱うアグリゲーターなら誰でもこれを目にする。ターゲットは週ごとにシフトする。pickerの再構築により、システムは敵対的なターゲットを迂回するためのより良い手段を得たが、トラフィックを完全に拒否すると決定したサイトを上書きすることはできない。我々の仕事は、協力的なケースで可能な限りクリーンなデータを提供し、敵対的なケースではフェイルファストを行うことだ。
Same-day comparison has noise. パーセンタイルチャートで示している24時間ウィンドウは、昨日と一昨日を比較している。曜日効果、ターゲットサイトの分散、およびプールの構成はすべて、2つのウィンドウ間でシフトする。我々は方向性に自信を持っている(7日間のチャートは4月28日にきれいな変曲点を示している)が、自身のワークロードに対して我々をベンチマークする場合は、少なくとも1週間にわたって比較を実行してほしい。
What's next
pickerの書き換えは基盤である。その後ろにキューに入れられているいくつかの項目:
インスタンス間で共有される品質スコアマップ。これにより、独立したマップを構築するのではなく、互いに学習するようになる。現在、各インスタンスはどのプロキシが良いかについての独自の図を保持している。それは機能するが、無駄である。すべてのインスタンスが並行して同じ学習コストを支払っているのだ。
信頼度ベースのピッキング。推測しているプロキシよりも、過去数分間に実際にテストしたプロキシを優先する。トラフィックがそれ自体でpickerをウォーム状態に保てない少量の顧客に役立つ。
そして長期的な展望: ターゲットごとの品質スコアが多くのシグナル(ターゲットのレイテンシプロファイル、時間帯のパターン、プールセグメントのヘルス)の1つになるように、より多くの決定をpickerに押し込む。これをホットパスを遅くすることなく実行するためのインフラストラクチャはすでに存在している。
最もコストの低いリクエストは、再試行する必要がなかったリクエストである。pickerの再構築は、選択時のより良いデータが、事後のより多くの試行に勝るという賭けである。最初の24時間の証拠は、それが正しい賭けであることを示している。