【入門編】HTTP/2におけるエラーコード(RST_STREAM)の分類と原因 – HTTPプロトコル・通信規格実践ガイド

こんにちは!Webの裏側を支えるネットワークの世界へようこそ。インフラエンジニアの視点から、普段私たちが何気なく使っているWebブラウザとサーバーの「裏側の会話」を紐解いていく連載です。

さて、私たちが日常的に使っているHTTP/2。1つの通信路(TCPコネクション)の中で、画像やテキストなどたくさんのデータを同時に並行してやり取りできる「マルチプレクシング」という魔法のような仕組みを持っていますよね。この「同時にたくさん運べる」という特性はWebを劇的に速くしてくれたのですが、同時に「マルチバースのように複雑化した通信のどこかでトラブルが起きたとき、どうやって片方だけをスマートに止めるか?」という新しい課題も生みました。

HTTP/1.1の時代であれば、何か致命的な問題が起きたらコネクションごと「プツン!」と切断するしかありませんでした。しかし、HTTP/2では家を一軒まるごと取り壊すのではなく、「問題のある部屋(ストリーム)だけをピンポイントで鍵をかけて締め出す」ことができるのです。

その主役こそが、今回深掘りしていく `RST_STREAM`(リセット・ストリーム)フレーム と、そこに添えられるエラーコードたちです。一歩ずつ、現実世界の例えを交えながら優しく紐解いていきましょう!

—

1. 郵便配達で例える「RST_STREAM」の世界

突然ですが、あなたの大切な自宅に、たくさんの荷物が届くシーンを想像してみてください。

HTTP/1.1の通信は、いわば「1本の細い道路を、1台のトラックが荷物を1つずつ運んでくる状態」でした。途中で荷崩れが起きたら、トラック全体が立ち往生してしまい、後ろの荷物はすべて足止めです。

これがHTTP/2になると、どうでしょう。「1本の大きな大通り(TCPコネクション)」の中に、何車線ものレーン(ストリーム)が作られ、複数の配達員が同時に荷物を運べるようになります。

ここで問題発生です。ある配達員(ストリームA)が運んでいる荷物の中身が、どうやらルール違反の危険物だったり、あて先不明で大混乱を引き起こしたりしていると発覚しました。
このとき、大通りそのものを通行止めにしてしまうと、他の元気に荷物を運んでいる配達員(ストリームBやC)まで迷惑を受けてしまいますよね。

そこで登場するのが、司令塔であるあなた(またはサーバー)が叫ぶ、こんな指示です。

> 「おい、その3番レーンの配達員!荷物はそのまま破棄して、今すぐ引き返せ!(RST_STREAM)」

この「なぜ引き返させるのか」の理由を明確にするラベルが、今回学ぶエラーコードというわけです。

—

2. 現場でよく出会う主要なエラーコードたち

RST_STREAMフレームには、「なぜこのストリームを強制終了するのか」を伝えるための32ビットのコードが載せられています。すべてを覚える必要はありません。実務の現場やデバッグで頻繁に顔を合わせる代表的な「主犯格」たちを、分かりやすく整理しておきましょう!

① `PROTOCOL_ERROR` (プロトコル違反です!)

  • どういう時?: 通信の「ルールブック」を破ったときに発生します。例えば、HTTP/2の仕様では「送ってはいけない順番でフレームを送ってしまった」「ルール外の変な値が設定されている」といった、お行儀の悪い振る舞い検知された場合です。
  • 現実の例え: 「申請書類のハンコが上下逆さまです!このレーンは無効です!」と突き返されるような状態です。

② `CANCEL` (もうこのリクエスト要らないや)

  • どういう時?: クライアント(ブラウザ)が自発的に「あ、やっぱり今の画像の読み込み、ユーザーがタブ閉じちゃったからもういらないや!」とキャンセルした時に送られます。エラーというよりは、お互いの「無駄な通信をやめようね」という優しさのシグナルです。
  • 現実の例え: ピザを注文した直後に「ごめん、やっぱりキャンセルで!」と電話するようなものです。

③ `INTERNAL_ERROR` (サーバー内部でエラーが起きました)

  • どういう時?: プロトコル自体は悪くないのに、サーバー側のプログラム(バックエンドのデータベースやアプリケーション)がクラッシュしたり、予期せぬ例外(NullPointerExceptionなど)をキャッチしたりした時に発生します。
  • 現実の例え: 配達員が荷物を受け取った直後、倉庫の中で荷物の棚がガラガラと崩壊してしまい、「あ、これもう届けられない……!」とパニックになった状態です。

④ `REFUSED_STREAM` (ごめんなさい、今は処理できません)

  • どういう時?: サーバーが「ちょっと今、アクセスが集中しすぎていて、この新しいリクエストを処理する余裕がないよ!」と、安全のためにわざと突っぱねる時に使われます。このコードがついたRST_STREAMを受け取ったクライアントは、「安全なエラーだったんだな」と判断して、後で自動的に再送(リトライ)を試みることができます。
  • 現実の例え: 人気のラーメン店で、行列が長すぎて店員さんが「お客さん、今日のスープ切れちゃったので、この注文は受け付けられません!」と丁重にお断りするようなイメージです。

—

3. 実務の現場でどう役立つ?トラブルシューティングの作法

「ふむふむ、エラーコードの意味は分かったけれど、実際の開発やインフラの現場ではどうやってこれを見つけるの?」と思いますよね。

日々の運用で、ユーザーから「なんだかこのページだけ画像が読み込まれなくて壊れるんだけど!」という報告を受けたとしましょう。そんなとき、私たちはブラウザの検証ツール(DevTools)や、ネットワーク解析の定番ツールである Wireshark や nghttp2 などのコマンドラインツールを使ってパケットのやり取りを覗き見します。

例えば、コマンドラインからHTTP/2の動作をテストする `nghttp` コマンドを使うと、次のようなログに直面することがあります。

nghttp コマンドを使って、あえて負荷が高い、あるいは特殊なサーバーへアクセスする例
$ nghttp -v https://api.example.com/heavy-resource

実行結果のログ(イメージ)
[ 0.050] send HEADERS frame
[ 0.080] recv RST_STREAM frame
[ 0.081] おおっと!ストリーム3番がサーバーから拒否されました!

このログを見た瞬間に、インフラエンジニアの頭の中では次のような思考プロセスが走ります。

1. 「お、RST_STREAMが返ってきているぞ。コネクション自体は切れていない(TCPは生きている)から、サーバーが元気な証拠だ」
2. 「エラーコードは `REFUSED_STREAM` だ。PROTOCOL_ERRORじゃないから、リクエストの書き方自体に不備があるわけではなさそうだ」
3. 「ということは、サーバー側がリソース不足(CPU負荷が高い、同時接続数制限に引っかかっているなど)を起こしている可能性が高いな。バックエンドのメトリクス(CPU使用率やコネクション数)を確認しに行こう!」

このように、エラーコードがピンポイントで原因を教えてくれるおかげで、広大なネットワークの海原から、一瞬で「調子の悪い原因」を特定できるようになるのです。

—

まとめ

今回は、HTTP/2の縁の下の力持ちである `RST_STREAM` と、その心臓部であるエラーコードについてお話ししました。

  • HTTP/2では、トラブルが起きたストリーム(レーン)だけを個別に強制終了できる。
  • `PROTOCOL_ERROR` は「ルール違反」、`CANCEL` は「自己都合キャンセル」、`INTERNAL_ERROR` は「サーバーの内部崩壊」、`REFUSED_STREAM` は「安全な拒否(混雑)」を意味する。
  • これらのコードを手がかりにすることで、インフラのトラブルシューティングが劇的にスピーディーになる。

ネットワークのプロトコルは、一見すると無機質なアルファベットの羅列に見えますが、その裏側には「どうすればお互いの通信を効率よく、かつ安全に行えるか」という先人たちの知恵と優しさがたくさん詰まっています。

次にブラウザのネットワークタブでエラーを見かけたら、「あ、今このストリームでこういう会話が行われていたんだな」と、パケットたちのドラマに思いを馳せてみてくださいね。それでは、また次回の技術解説でお会いしましょう!

コメント

タイトルとURLをコピーしました