同じ回線でWebページは開けるのにAPIだけタイムアウトする——開発者から最も多く寄せられる相談のひとつです。原因は「通るかどうか」ではなく「耐えられるかどうか」にあります。Webリクエストはすぐ終わりますが、1回のAPI呼び出しは長時間出力し続けることがあります。Webなら失敗時にユーザーが再読み込みしますが、APIはプログラムが再試行するかエラーを返すだけです。つまりAPIに向く回線かどうかは、ピーク速度ではなくジッター、出口の安定性、長接続の維持力で判断します。
本記事に速度測定のスクリーンショットは載せません。回線の挙動は時間帯や地域で変わるため、他人のスクリーンショットの数字に参考価値はありません。以下では再現できる測定方法と判断基準を示しますので、自分のネットワーク環境でそのまま試してみてください。
Webは開くのにAPIがタイムアウトする、差はどこで生まれるか
1回のAPI呼び出しを分解すると、経路は4段階に分かれます。名前解決、TCP接続、TLSハンドシェイク、そして最初のバイトを待ち後続データを受け取る段階です。Webアクセスはこの4段階がどれも短く、静的リソースは通常は近接拠点から配信されます。一方APIエンドポイントは多くの場合ドメインが1つだけで近接配信もなく、4段階すべてが自分が接続する回線に乗ります。どこか1段階でも待ち行列が発生すれば、クライアントから見える結果はまずタイムアウトです。
ストリーミング応答はこの問題を増幅します。SSEは1回の応答を多数の小さな断片に分けて順次送り出すため、途中のどこか1ホップがバッファリングすると、クライアントからは「止まったまま」に見え、やがて読み取りタイムアウトになります。したがってこの種の問題は、総所要時間ではなく、最初のバイトまでの時間とデータとデータの間隔で判断します。
まず「通るか」と「安定するか」を分けて測ります。1回のリクエストはその瞬間に通ったことしか示しません。連続して複数回サンプリングして初めて回線の性格が見えます。記録するときは解決・接続・ハンドシェイク・最初のバイト・総所要時間の5項目に分けておけば、問題が出たときにどこで詰まったかが分かります。
3つの回線形態:直結・中継・専用線
同じ「高速化」と書いてあっても、下の物理経路はまったく違うことがあります。よくある3形態は次のとおりです。ここでは定性的な比較のみで、速度の数値は含みません。
| 形態 | トラフィックのおおよその流れ | ジッターとパケットロス | 固定出口 | 向いている呼び出し方 |
|---|---|---|---|---|
| 直結 | ローカルから海外ノードへ直接接続し、全区間が公衆インターネットの国際出口を通る | 夜のピーク時間帯に変動が大きい | ノードの割り当て方式による | デバッグ、軽量なリクエスト |
| 中継 | 最寄りの入口に入り、トンネル経由で国外のノードへ抜ける | 直結より安定。入口の品質に依存 | 多くは固定可能 | 通常のAPI呼び出し |
| IEPL 専用線 | ローカルから入口までは専用回線で国外へ抜け、公衆インターネット国際出口の混雑点を通らない | 通常はより小さい | 固定しやすい | 長接続、ストリーミング出力、バッチ同時接続 |
直結は最もコストを抑えられますが、運任せでもあります。経路全体が公衆インターネットの国際出口を通るため、夜のピークの混雑がそのままAPI呼び出しに伝わります。中継は「ラストワンマイル」を最寄り入口に置き換え、国外へ出る区間をトンネルで通します。安定性は入口の品質とトンネル自体に依存します。IEPL 専用線はレイヤ2の専用線で、公衆インターネット国際出口の混雑点を通らないためジッターは通常より小さくなりますが、価格は高く、選べる地域も限られます。
契約前に確認しておきたいのは4点です。入口はどの都市か、出口アドレスは固定か、購入するプランは具体的にどの形態か、回線障害時にどう切り替えるか。多くの「高速化」という謳い文句は、この4問に耐えられません。
固定出口:API 呼び出しで最初に確認したい項目
Webブラウジングでは出口アドレスが変わっても気になりませんが、API呼び出しでは大きな問題になります。理由は4つあります。
- ホワイトリスト。多くのプラットフォームは呼び出し元アドレスをホワイトリストに登録できます。出口が変わればリクエストは即座に拒否されます。
- セッションの一貫性。一部のサービスはセッションを送信元アドレスに紐づけており、アドレスが揺らぐと二段階の検証やレート制限を誘発します。
- トラブルシューティング。出口が固定されていればこそ、ログの「このリクエストはどこから出たか」に一意の答えが出ます。出口が飛び回ると、ログの突き合わせは単なる肉体労働です。
- チームでの共用。複数の開発機がそれぞれ外へ出ると出口は分散します。海外ゲートウェイ1台と安定したトンネル1本にまとめれば、出口は1つに収束し、ルールも書きやすくなります。
固定出口は専有出口と同じではありません。共有出口に他に頻度の高いリクエストが流れていると、宛先サイトのレート制限が自分に降りかかることがあります。症状は、コードを何も変えていないのに一定時間APIがレート制限エラーを返し続ける、というものです。
安定性が重要な呼び出しでは、契約前に2点を確認してください。出口は共有か専有か、再接続後にアドレスが変わるか。この2つの答えは、どんな速度の説明よりも重要です。
同時接続とタイムアウト:最も設定を誤りやすい2箇所
同時接続は「同時に開いているストリーム」で数える。QPS では数えない
HTTP/2の多重化により複数のリクエストが1本の接続を共有するため、いくらでも並列にできるように見えます。しかしサーバー側にも中間ノードにも同時ストリーム数の上限があり、超えるとリクエストはキューで待たされ、最初のバイトまでの時間が伸び、最終的には同じくタイムアウトとして現れます。ストリーミングAPIでは特に注意が必要です。1本のリクエストは出力が終わるまで接続を占有し続けるので、同時接続数は同時に開いているストリームで数えます。
クライアント側のコネクションプールも大きくしすぎないこと。プールの意味は再利用であって、数を積み上げることではありません。接続数が回線の容量を超えれば、すべての接続が遅くなるだけです。バッチ処理はキューとレート制限を使い、同時接続を「安定して最初のバイトが取れる」範囲に抑えるほうが、後からタイムアウトを調整するより効果的です。
タイムアウトは3層に分けて設定する。1つの数字で全部を管理しない
- 接続タイムアウトはTCPとTLSのハンドシェイクを対象にします。この段階での失敗は経路が通っていない証拠で、時間を延ばすのではなく回線を変えるべきです。
- 最初のバイトのタイムアウトはサーバー側の待ち行列と準備時間を対象にします。余裕を持って設定してください。接続タイムアウトとは別物です。
- 読み取りタイムアウトは、ストリーミング応答では「データとデータの間隔」で計算します。総時間で長い出力を打ち切らないでください。
- リトライは冪等なリクエスト、または未受理が明確なエラーにだけ行います。生成系のリクエストをむやみに再試行すると、クレジットを二重に消費します。
- バックオフは指数バックオフにランダムなジッターを加え、バッチ全体が同じ秒に一斉再接続するのを避けます。
まずコマンドラインで5つの区間を計測し、そのうえでどのパラメータを調整するかを決めます。
curl -o /dev/null -s \
-w 'dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} ttfb=%{time_starttransfer} total=%{time_total}\n' \
"$API_BASE/v1/models"
クライアント側で接続と読み取りを分けて設定するのが、最もコストの低い一歩です。
import httpx
# ここの数値はあくまで出発点。自分の回線状況に合わせて調整する
timeout = httpx.Timeout(connect=5.0, read=120.0, write=30.0, pool=5.0)
with httpx.Client(timeout=timeout, http2=True) as client:
with client.stream("POST", f"{base}/v1/chat/completions", json=payload) as resp:
resp.raise_for_status()
for line in resp.iter_lines():
handle(line)
プロトコルの選び方:よく使われる6種類の違い
プロトコルは最優先の判断材料ではありませんが、ハンドシェイクのコストと弱い回線での挙動を左右します。次の表は違いだけを示すもので、「どれが最強か」を決めるものではありません。
| プロトコル | トランスポート基盤 | 特徴 | 注意点 |
|---|---|---|---|
| Shadowsocks | TCP / UDP、SOCKS5 相当のセマンティクス | 軽量でハンドシェイクのコストが小さい | 多重化を内蔵せず、高並列時に接続数が増えやすい |
| VMess | TCP、TLS または WebSocket を被せられる | エコシステムが成熟し、設定項目が多い | ヘッダのオーバーヘッドが VLESS より大きい |
| VLESS | TCP + TLS、XTLS や uTLS と組み合わせ可能 | 自身は暗号化せず、オーバーヘッドが低い | 安全性は完全に TLS 依存。設定を誤ると無防備 |
| Trojan | TLS、通常の HTTPS トラフィックに偽装 | 443 番ポートのトラフィックに混ざり、単独では識別されにくい | 証明書に依存。証明書に問題が出ると即座に接続不可 |
| Hysteria2 | QUIC、UDP を使用 | パケットロスに強く、弱い回線でもスループットが出やすい | UDP が帯域制限されることがあり、TCP 系へ切り替えられる必要がある |
| TUIC | QUIC、UDP を使用 | 接続確立が速く、コネクションマイグレーションに対応 | 体感はキャリアの UDP の扱いに左右される |
実用的な判断をいくつか。TCP 系のプロトコルは中間機器にやさしく、QUIC 系はパケットロスが目立つ回線で快適ですが、UDP に依存するため帯域制限に遭ったら TCP 系へ戻せる必要があります。VLESS は自身では暗号化せず、安全性は完全に TLS に委ねます。Trojan は証明書に依存するため、自動更新を怠るとある日突然つながらなくなります。新しさを追うより、使っているクライアントが対応していて保守が活発なものを選ぶほうが現実的です。
クライアントとサブスクリプション:プラットフォームの違いが調査に直結する
- Windows と macOS:システムプロキシはシステム設定を読むプログラムにしか効きません。コマンドラインツールや多くの SDK はシステムプロキシを読みません。
HTTPS_PROXY環境変数を設定するか、TUN モードで全トラフィックを引き受ける必要があります。 - Linux:システムプロキシという層がなく、環境変数か TUN + ポリシールーティングで対応します。コンテナ内でタスクを動かすときは、プロキシ変数が自動では引き継がれない点に注意してください。
- 振り分けルール:API ドメインには専用のルールを1本書き、広い範囲のルールに巻き込まれないようにします。DNS の解決方式も振り分けとセットで確認してください。そうしないとドメインの解決結果と実際の出口が食い違い、調査時に誤判断します。
- サブスクリプションのインポート:サブスクリプションリンクは本質的にノード一覧で、クライアントが定期的に取得して更新します。クライアントを変えるときは同じサブスクリプションをインポートするのが優先で、ノードを手で写さないこと。パラメータを1つ写し漏らすと「接続はできるが動かない」状態になります。
コマンドラインツールがシステムプロキシを読まないのはよくある落とし穴です。まず環境変数か TUN モードが効いているか確認し、そのうえで回線の問題かどうかを判断すれば、調査時間を半分に減らせます。
選定チェックリスト:まず照合できる項目、次に謳い文句
サービスを選ぶときは、照合できて主観に依存しない項目から見てください。次の4項目は当サイトが公開している数値で、そのまま照合できます。
- ✅ コマンドラインで解決・接続・ハンドシェイク・最初のバイト・総所要時間を分けて記録し、時間帯を変えて複数回サンプリングする。見るのは最速の1回ではなくジッター。
- ✅ 何度も再接続したうえでエコー用アドレスのAPIを叩き、出口が変わっていないことを確認する。
- ✅ 接続タイムアウトと読み取りタイムアウトを分けて設定し、ストリーミングAPIは読み取りだけ個別に緩める。
- ✅ バッチ処理はキュー経由にし、同時に開くストリーム数を制限する。
- ✅ 振り分けルールでAPIドメインを個別に記載し、DNSの解決方式がルールと一致していることを確認する。
- ✅ クライアントを変えるときは同じサブスクリプションをインポートし、ノード一覧が正常に更新されることを確認する。
- ❌ Webページの表示速度からAPIの挙動を推測する。
- ❌ 1つの総タイムアウトですべてのリクエストを管理する。特にストリーミング応答で。
- ❌ 生成系のリクエストを考えなしに再試行する。
- ❌ 接続できた=すべてのプログラムがこの回線を通っている、と考える。
あと2点、常識ではあるものの見落とされがちなこと。返金条件は契約前に確認してください。当サイトは7日間の理由不問返金があり、自分のテストを一巡するには十分です。支払い方法は Alipay、WeChat Pay、USDT に対応しており、チームでの購入もどの方法でも帳簿と突き合わせられます。登録に必要なのはユーザー名とパスワードだけで、メールアドレスは不要です。入力項目が1つ減れば、不安も1つ減ります。
結論:パラメータより順序
1つだけ覚えるなら。「通るかどうか」と「安定するかどうか」を2回のテストに分けること、接続・最初のバイト・読み取りの3段階のタイムアウトを分けて設定すること。この2つを済ませれば、「APIがいつもタイムアウトする」という不満の大半は自然に消えます。