0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

レート制限の上限は、通したい相手の速度ではなくサーバーが捌ける量から決める ─ 前段・後段の上限とクローラーの点検リスト

0
Posted at

この記事でできること

公開ページにIP単位のレート制限を掛けているのに、上限の内側に収まったクローラー1体だけでサーバーが詰まることがあります。個人開発している技術記事キュレーションサービスDevPickでは、ページ描画の上限を240/分にしていたところ、毎分170〜320ページを取りに来たクローラーでバックエンドのワーカーが入れ替わり続け、他の閲覧者にも502が出ました。上限は90/分に下げています。

この記事は、そのときに見直した点を、ページ描画にレート制限を掛けるときの点検リストとしてまとめたものです。対象は、SSRのフロントエンドがバックエンドAPIを呼ぶ構成で、小さいVPS1台で動かしているサービスです。

前提:上限が前段と後段の二段になっている

DevPickでは、Next.jsのproxy(ページを描画する前に走る処理)がIPごとにページ数を数え、上限を超えた分には503とRetry-Afterを返しています。その後ろでは、FastAPIのバックエンドがAPIの呼び出し回数をIPごとに数えています。

前段のページ上限を置いているのは、検索クローラーへ正しいステータスを返すためです。SSRの途中でバックエンドの429に当たると、ページはエラー境界の500になってしまいます。前段で先に止めれば「過負荷なので後で来てほしい」という意味の503を返せます。

以下の点検項目は、この二段構成を前提にしています。

点検1:上限の根拠に「サーバーが捌ける量」が入っているか

上限の値を決めた理由を書き出してみます。「クローラーの通常の速度を止めないため」「普通の閲覧者が超えないため」のように、通したい相手の速度だけが根拠になっている値は要注意です。その値いっぱいでアクセスされたときにサーバーが耐えられるかを、誰も確かめていないからです。

レート制限は、上限の手前までは何も止めません。上限は「この速度までは来てもよい」という宣言でもあるので、上限いっぱいのアクセスが10分、20分と続いてもサーバーが処理しきれるかで見積もります。通したい相手の速度は下限として使い、上限はサーバーの処理能力から決めて、その間に値を置きます。両者が逆転していたら、上限の値を調整する前にサーバーの処理能力かページの重さを見直す必要があります。

点検2:1ページが裏で何回APIを呼ぶかを掛けているか

ページの上限とサーバーの負荷は1対1ではありません。DevPickの記事詳細ページは、SSRで記事本体・関連記事・画像の確認と、バックエンドAPIを3回呼びます。ページ上限が90/分でも、1つのIPからバックエンドへ最大で毎分270回の呼び出しが届きます。

ページ単位の上限を決めるときは、ページの種類ごとにSSRが呼ぶAPIの回数を数え、一番重いページで掛け算した数をサーバーの処理能力と比べます。ページ数だけを見ていると、実際の負荷を数分の一に見積もってしまいます。

点検3:前段と後段の上限の大小関係を崩していないか

前段で503を返す仕組みは、後段のSSR用の上限が、前段のページ上限で通したアクセスを受け止められるときだけ働きます。APIごとの上限なら「ページ上限 × そのページがそのAPIを呼ぶ回数」、バックエンド全体の上限なら「ページ上限 × 1ページの合計呼び出し回数」を下回らないようにします。これが逆転すると、前段で止まる前にバックエンドの429へ当たり、ページは500に戻ります。

  • 前段の上限を下げる変更は、この関係を崩さないので、前段だけを変えれば済みます
  • 前段の上限を上げるときは、後段の上限も一緒に見直します
  • 2つの値は別々のファイル・別々の言語にあることが多いので、大小関係をテストで確かめておくと、片方だけ変えたときに気づけます

点検4:IP単位の上限で守れない巡回への備えがあるか

IP単位の上限は、1つのIPからの集中には効きますが、複数のIPから分散したアクセスには効きません。点検1の見積もりも「1つのIPが上限いっぱいで来た場合」までしか保証しないので、次も確かめます。

  • IPに依らない上限(全体の同時描画数、全体の毎分のページ数)があるか。無いなら、それが無い状態で何本の巡回まで耐えられるかを把握しているか
  • 同時描画数を数えるなら、数える場所で描画の開始と終了の両方を知れるか。リクエストを受けた時点で1回だけ走る処理では、開始は数えられても終了は数えられない
  • 全体の上限を超えたときも、個別の上限と同じく503とRetry-Afterを返すか

点検5:下げた上限が検索クローラーの巡回を減らしすぎないか

上限を下げると、クローラーに返す503は増えます。Googleのドキュメントでは、5xxや429を受け取ったクローラーはそのサイトのクロール速度を一時的に下げ、エラーが減れば徐々に戻す、とされています。一方で、同じURLが何日も5xxを返し続けると、インデックスから外れることがあるとも書かれています(HTTP ステータスコードの扱い、クロール頻度を下げる)。

一時的に503を返すのは、サーバーが詰まって502や500を返すよりはずっとましです。それでも、上限を下げたあとはSearch Consoleのクロールの統計情報で、クロール数やサーバーエラーの割合が大きく変わっていないかを見ておきます。

ワーカーが入れ替わり続けたときの切り分け方

同じ症状が出たときは、次の順で確かめると原因にたどり着きやすくなります。

  • ワーカーが入れ替わった時刻を、アプリのログから拾う
  • その時間帯にアクセスログを絞り、User-Agent別・IP別にリクエスト数を数える。静的ファイルを除いた、ページ描画の件数で見る
  • 特定のIPやUser-Agentに偏っていれば、毎分のページ数を上限と比べる。上限で503になった件数がほとんど無いのに詰まっていれば、上限の値そのものが大きすぎる
  • 偏りが無く、多くのIPに分散していれば、IP単位の上限では防げない種類の負荷なので、点検4に戻る

まとめ

  • レート制限の上限は、通したい相手の速度だけでなく、上限いっぱいで来られてもサーバーが捌けるかで決める
  • ページの上限は、1ページがSSRで呼ぶAPIの回数を掛けてからサーバーの処理能力と比べる
  • 後段のSSR用の上限が、前段のページ上限 × API回数を下回らない関係を保つ。前段を上げるときは両方を見直す
  • IP単位の上限は分散した巡回には効かない。全体の上限は別に用意する
  • 上限を下げたら、検索クローラーの巡回が落ちすぎていないかをSearch Consoleで見る

240/分という値をなぜ選び、どう90/分へ下げたかの経緯は、Zenn版に書いています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?