「おま環」で終わらせない!ネットワークエラーを追う
はじめまして
こんにちは。スマサテの開発を担当している由利です。データ/インフラを担当していますが、基本的には何でもやります。 以前、技術的な記事を個人的なブログで10年ほど書いていました(※すでに爆破済み)が、Zennでははじめての執筆となります。よろしくお願いします。
Abstract
提供しているサービスの特定のページに特定のユーザーがアクセスしたときのみ、ページ上の機能が動作しないという報告が定期的に発生していました。
原因はユーザー側のアクセス環境(おそらくWebプロキシサーバー)の制限により、短期間に大量のリソースを取得しようとすると、HTTPリクエストが拒否されることでした。
特定のユーザーのアドブロックなどのブラウザ拡張機能や社内プロキシの制限などによって特定の機能が動かないことはよくあると思いますが、こういったものはいわゆる「おま環」「お前の環境が原因(だからお前でなんとかしろ)」と言われてしまうこともあります。
本来アクセスできるべきリソースがブラウザ拡張機能や社内ネットワークの制限を受けてアクセスできなくなっているのだから、利用者側が解決すべき。
それはそれで正しくはあるのですが「御社の社内ネットワークの制限緩和を依頼してみてください」なんて案内してみても、その会社のシステム管理者が適切な対応を確実にしてくれるとは限りませんし、たった1つのサービスを利用するために全社の制限を緩和できない、という考えもできるでしょう。
それを踏まえてエンドユーザーの気持ちに立ってみると「お金を払って使っているのに使えないじゃないか。うちのシステム管理者は設定は変えてないっていうし、スマサテはこっちのネットワークが悪いっていうし。サービスが使えないなら乗り換えるしかないじゃないか…」という気持ちになってしまうかもしれません。というか、私ならそう思うと思います。
だから「おま環」と言いたくてもそれは言わず、なんとかできることを模索していき、直せるところがあれば直したいと思います。
今回の記事では問題が発生してから解決に至るまでにやったこと、考えたことなどを時系列順に列挙していきたいと思います。すでに答えは書いてしまっていますが、何が原因だろうと推察しながら読んで頂けると面白いかと思います。トラブル対応だいすき❣というエンジニアはあんまりいないと思いますが、最後まで読んで頂けると嬉しいです。
なお ジュニアレベルのエンジニアでも読めることを想定して書いているので多少冗長な説明と思われる部分もあります がご容赦ください。
問題発生、調査開始
サービスの問い合わせフォームから以下のような問い合わせがありました。
日時: 2025年X月XX日 15:00
会社: 〇〇株式会社 〇〇本部
担当: 〇〇 〇〇 様
メール: xxxxxx@example.com
URL: https://example.com/page/id-xxxxxxxxx
内容: レポートダウンロードができない
ユーザーからのお問い合わせ内容は「レポートダウンロードができない」という一文のみでした。
これをうけてすぐ営業の方からユーザーの方に電話でヒアリングを行っていただき、エラーが発生しているページのIDなどを確認していただきました。その後、すぐにレポートが出力したいと焦っておられるとのことで、別途こちらで出力したファイル一式を送信していただきました。
スマサテではこういった障害報告がなされた場合の対応フローとしては、当番制および手が空いているエンジニアが積極的に対応するという形式をとっています。チーム間の役割がゆるくオーバーラップしていること、皆当事者意識を持っていることなどもあって、たいていの障害はすぐに積極的な調査対応が始まります。
というわけで調査が開始されました。最初に調査してくださった営業の方では再現は出来なかったとのこと。再現できればあとはもうデバッグしていけばいいだけとも言えますが……。最初に調査にあたったエンジニアの方も、ヒアリングした操作手順では再現出来ず。その時の手順とは大まかに以下のようなものでした。
- 該当のページにアクセス
- 「レポート出力」ボタンをクリック
- 本来であればここでモーダルが表示されるはずが、画面が暗転したままになってしまう
特定のブラウザに限られた挙動かどうかをテストするため、ユーザー側で使用しているブラウザで実施してみても 再現しませんでした。 他のユーザーからの問い合わせを確認してみても、同様の現象が発生しているという報告はありませんでした。しかし、その問い合わせがあった会社の社内では他のユーザーも同様の現象が発生しているとのこと。特定の会社の特定のユーザーに限られた現象のようです。
調査をしている中で再びユーザーから電話連絡があり「何度か試したところ正常動作するようになった。しばらく様子を見たい」ということでいったんは事態は収束しました。
この時点での予想は、おそらくはネットワーク由来の偶発的な要因で必要なリソース(jsファイル)の一部が読み込まなかったのだろう、というものでした。
問題の再発と原因の推測
数日後に再び同じユーザーから「また同じ現象が発生した」との連絡があり、今度はWeb会議を通じて、エンジニアがユーザーの操作を確認できました。その際、Chromeのデベロッパーツールを開いて操作を確認していくと、2点のことがわかりました。
- Google Analyticsが提供しているJavaScriptファイルが
net::ERR_CONNECTION_RESETで取得できていない。 - 弊社のサービスが提供しているJavaScriptコードで
'google' is not definedというエラーが発生している。 - 1, 2 のエラーは記載の順序で発生している。
またこれまでも 同様の問い合わせが2回ほど発生 しており、過去のケースでは net::ERR_HTTP2_SERVER_REFUSED_STREAM というエラーが発生して必要なリソース(画像など)が取得できていませんでした。
ここまで分かった段階で私のところにも調査に協力してほしいと依頼が届き、調査を始めました。
原因の追求
私が真っ先に考えたシナリオとしては「Googleが提供しているJavaScriptファイルがネットワークエラーにより読み込めなかったため、それを参照している後続のスクリプトでエラーになった」でしたが、これは違っていました。
google オブジェクトを提供しているのはGoogle Maps APIであって、ネットワークエラーになったGoogle Analyticsとは別です。言い換えると、 google オブジェクトを提供しているスクリプトの読み込みには失敗しいないのです。
Google APIのスクリプトの読み込みは成功しているはずなのに 'google' is not defined というエラーが出てしまうのはこれなぜなのか……。
次に考えたのは、 Google Maps API の読み込み時にコールバックが正しく設定されていないのでは?ということでした。
Google Maps APIの初期化の方法は、
- Dynamic Library Import
- ダイレクト スクリプト読み込みタグ
- NPM js-api-loader パッケージ
の三種類があるようです。今回のケースでは2番目のダイレクト スクリプト読み込みタグを使用していました。「ダイレクト スクリプト読み込みタグ」という仰々しい名前がついていますが、要は <script> タグを使ってGoogle Maps APIのスクリプトを読み込むという方法です。 実際に指定されていたタグが以下のとおりです。怪しいところがありますが気づきますでしょうか?
<script src="https://maps.google.com/maps/api/js?key=(中略)&callback=Function.prototype"></script>
callback=Function.prototype というのは、Google Maps APIの初期化時にコールバック関数を指定するためのパラメータのはずです。このコールバックにFunction.prototypeが指定されているのは、つまり何もしない関数を指定していることになります。Google Maps APIのコードが非同期で読み込まれているはずなのに、その完了を受け取るコールバックが何もしていなくていいのでしょうか(よくない)。
記事執筆時点のGoogle Maps APIドキュメントには以下のような記述があります。
loading: Maps JavaScript API が使用できるコード読み込み戦略。async に設定すると、Maps JavaScript API を同期的に読み込まないことと、スクリプトの load イベントによって JavaScript コードをトリガーしないことが明示されます。パフォーマンスを高めるため、可能であれば async に設定することを強くおすすめします。(Maps JavaScript API を利用できる場合は、代わりに callback パラメータを使用してアクションを実行します)バージョン 3.55 から利用できます。
callback: Maps JavaScript API が完全に読み込まれた後に呼び出されるグローバル関数の名前。
loading を async にすると非同期でこのスクリプトが処理されるようです。Web標準では <script> タグに async 属性をつけることで非同期でスクリプトを読み込めますが、Google Maps APIでは loading パラメータを async に設定することで同様の効果を得られるようです。ただ、今回は loading パラメータは設定されておらず、callback のみが指定されています。callback が指定されていたらコードの読み込みは非同期になる(でないとコールバックを指定する意味がないため)と思っているのですが、はっきりとドキュメント中ではそれが明言されていません。一応、原文と思われる英語版も確認しましたが同などの記述でした。
なので、テストしてみました。
<script src="https://maps.google.com/maps/api/js?key=(中略)&callback=Function.prototype"></script>
<script>
// 実際にはここに色々なコードやHTMLがある
</script>
<script>
// 後続するGoogle Maps APIを利用するコード内
console.log(typeof google);
</script>
すると、出力は undefined となりました。ただ、この状況の再現もシビアで、上掲のコードをそのまま実行してもGoogle Maps APIの読み込みのほうが先に完了してしまうようです。私の手元の環境では、スマサテのサービスのアプリが出力しているDOMでのみ再現できました。再現可能なコードを提示できないのが歯がゆいですが、Google Maps APIのスクリプトはcallbackが指定されたときは非同期にスクリプトの読み込みを行っているようだ、という裏取りはできました。内部実装としては、最初にコンパクトなローダーのみが同期的に読み込まれ、メインのコードだけ非同期で読み込まれるようになっているのでしょう。
というわけで、原因としては以下と判断しました。
- ユーザーの環境において、Google Maps APIのスクリプトが同期的に読み込まれ、コンパクトなローダー部分のみが読み込まれた
- その後、Google Maps APIのメインのコードが非同期で読み込まれた
- 通常はGoogle Maps APIを利用するコードに到達するまでにGoogle Maps APIのコードの読み込みが完了することがほとんどだが、
当該ユーザーの場合は何らかの理由で読み込み完了前にGoogle Maps APIを利用するコードが実行されてしまいエラーになった
これとは別の問題として、
- 以上の事象とは関係なく、Google Analyticsのスクリプトや画像など、必要なリソースがネットワークエラーで取得できないことがある
ということも考えました。つまり、ネットワークエラーとGoogle Maps APIの読み込みの順序に関する問題は別々の問題である、という判断です。
もしかしたらGoogle Analyticsのスクリプトが正しく読み込まれないことでGoogle Maps APIを利用するコードにたどり着くまでの時間が短くなり、今回エラーが発生したのかもしれないということも考えられますが、その裏取りは難しいです。
ネットワークエラーになる要因としてはその内容が connection reset や refused stream など、サーバー側の制限に起因しているものが多く、さらに特定の会社のユーザーでのみ発生していることを考慮するとプロキシサーバーで短時間でのリクエスト数の制限に引っかかっている可能性が高いと考えました。
現状得られる情報からは確度が高いシナリオが上記のものであると判断し、対策を打つこととします。
対策
非同期で読み込まれるGoogle Maps APIの実行順序制御
まず、非同期で読み込まれるGoogle Maps APIの実行順序に関しての対策です。コールバックを正しく設定し、Google Maps APIの読み込みが完了した後にコードを実行するようにするのが正攻法です。
しかし、問題が発生している画面は古き良きjQueryが多用されているページであって影響範囲を調査するのが難しい事情がありました。コールバックを受け取ったあと、どのスクリプトをどのような順序で実行すれば同などの動作をするのか……。もともと順序保証されていないコードで現状動いているものを順序保証してしまったらまた次なるバグを生み出してしまう可能性がある 、これを一番危惧していました。
そういった背景があるためにこの画面のメンテナンス工数は増えており、 React で実装し直す作業がすでに進んでいます。ということは、修正対象のコードはいずれ破棄されるコードですから、ここで大きな工数を使った修正は行いたくないです。さらに特定のユーザー環境でのみ発生する発生頻度の低い問題に対処するために影響範囲を広げるのも避けたいです。
というわけで今回は正攻法での修正をやめ、泥臭いが影響は最小限になる方法を取ることにしました。
現象が発生している箇所で google オブジェクトが定義されていることを確認し、定義されていなければ待つ、定義されていればその後のコードを実行するという方法です。
function waitForGoogleMaps(maxRetries = 3, intervalMs = 1000, onReady) {
let attempts = 0;
const check = () => {
if (typeof google === 'object') {
onReady();
} else if (attempts < maxRetries) {
attempts++;
setTimeout(check, intervalMs);
} else {
console.error('Google Maps API not available after waiting.');
}
};
check();
}
waitForGoogleMaps(20, 1000, () => {
// ここに 元々実行されていたコードをそのまま移植
});
JavaScriptでは任意のコードを明示的に並列実行できない(Web Workerなど例外はありますが)ため、代わりに setTimeout を使って指定時間語にもう一度 check をイベントループに積み実行されるようにします。
これでメインスレッドをブロックせずに、Google Maps APIの読み込みを待てます。また、すでにこのコードが読み込まれたときに google が定義されていた場合はすぐに onReady が実行されますので、元々この事象が発生していなかったユーザーに対してはほぼ影響がありません。
ビジーループではだめです。つまり、以下のようなコードです。
while (typeof google !== 'object') {
// google が定義されるまで待つ
}
// ここに 元々実行されていたコードをそのまま移植
これだとメインスレッドをブロックしてDOMの描画まで止めてしまい、画面がフリーズしてしまいます。ブラウザの実装次第ですが、最悪のパターンはGoogle Maps APIのスクリプトの読み込みも行われず永遠にフリーズするかもしれません。
ネットワークエラーの対策
もう一点、ネットワークエラーの対策が必要です。過去のケースでは
net::ERR_HTTP2_SERVER_REFUSED_STREAMnet::ERR_CONNECTION_RESET
という2つのエラーが発生していたことを確認しています。スマサテのサービスのフロントエンドにはAWS Application Load Balancer(以下ALB)が配置されており、
ALBはHTTP/2設定を有効にしています。この2つのエラーは Google Chrome が表示しているエラーですが、それぞれ
- HTTP/2 REFUSED_STREAM error
- TCP RESET
に対応しています。
HTTP/2 REFUSED_STREAM error
あまり見慣れないエラーなのでRFCにあたってみました。Web標準技術は最終的にはRFCを見るのが最も確実です。
RFC 7540に記述があります。
In HTTP/1.1, an HTTP client is unable to retry a non-idempotent
request when an error occurs because there is no means to determine
the nature of the error. It is possible that some server processing
occurred prior to the error, which could result in undesirable
effects if the request were reattempted.HTTP/2 provides two mechanisms for providing a guarantee to a client
that a request has not been processed:o The GOAWAY frame indicates the highest stream number that might
have been processed. Requests on streams with higher numbers are
therefore guaranteed to be safe to retry.o The REFUSED_STREAM error code can be included in a RST_STREAM
frame to indicate that the stream is being closed prior to any
processing having occurred. Any request that was sent on the
reset stream can be safely retried.Requests that have not been processed have not failed; clients MAY
automatically retry them, even those with non-idempotent methods.
かいつまんで要約すると…
HTTP/1.1では冪等でないリクエストをリトライできなかった。サーバー側で処理が一部進んでいた可能性があり、安全なリトライができる保証がなかった。HTTP/2では、リクエストが全く処理されなかったという保証をするための仕組みが2つある。それがGOAWAYとREFUSED_STREAM。クライアントは、冪等でないメソッドであっても自動的に再試行してもよい。
ということになるかと思います。
おそらく、顧客の社内ネットワークのプロキシにより同時接続数が制限されており、制限が超えた場合にALBがHTTP/2のストリームを拒否しているのではないかと考えました。このエラーが出たときのChromeデベロッパーツールが表示したエラーメッセージをもう一度よく確認します。
まず、デベロッパーツールのコンソール上の表示は
- 大量の画像リソース(300個ほど)の読み込みが途中から
net::ERR_HTTP2_SERVER_REFUSED_STREAMでエラーとなっている - その後、jQueryから発せられた複数の非同期POSTリクエストが
net::ERR_CONNECTION_RESETでエラーとなっている
となっています。一方でネットワークタブの表示は 2. リクエストのみがエラーとして表示されています。
以上をすべて踏まえると、
- 大量の画像リソース (300個ほど) の読み込みが社内プロキシサーバーの同時リクエスト数に引っかかりリトライ可能な
REFUSED_STREAMエラーとなっている - リトライ可能なので画像のリソースは再度リトライされて正常に取得できている
- jQueryを用いて実施したPOSTリクエストはリトライ処理を実装していないため正常に処理されていない
という状況でしょう。
TCP RESET
TCP RESETは、レイヤ7(アプリケーション層)でのエラーですが、TCP RESETはレイヤ4(トランスポート層)のエラーです。TCPコネクションそのものがRSTフラグによって切断されてしまいます。クライアント側がエラーとして通知しているので、おそらくはサーバー側、つまりエンドユーザーから見たときの社内プロキシサーバー側からTCP RSTを送出したのではないかと考えました。
RFC 9293にTCPヘッダのフォーマットが載っています。
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| [Options] |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :
: Data :
: |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Note that one tick mark represents one bit position.
Figure 1: TCP Header Format
TCPヘッダのRSTフラグが立てられていたパケットを受信した場合、TCPコネクションの状態は即座にCLOSEDになります。厳密には以下のRFC記述のとおりですが、接続が確立したあとであれば即座に接続が切断されCLOSEDになると理解して良いでしょう。
The receiver of a RST first validates it, then changes state. If the receiver was in the LISTEN state, it ignores it. If the receiver was in SYN-RECEIVED state and had previously been in the LISTEN state, then the receiver returns to the LISTEN state; otherwise, the receiver aborts the connection and goes to the CLOSED state. If the receiver was in any other state, it aborts the connection and advises the user and goes to the CLOSED state.
厳密な説明は上記のとおりですが、要するにクライアントブラウザ視点で見れば「必要なリソースを取りに行ったらサーバー(おそらく社内プロキシ)が突然接続を遮断してきた」ということになります。
なぜそのような挙動をするのでしょうか。おそらくですが、このエラーが出ているのはGoogle Analyticsのドメインのリソースでのみ確認しているので、プロキシサーバーで選択的にGoogle Analyticsのリソースをブロックしているのではないかと予想しています。想像ですが、プロキシサーバー製品のプリセット設定でWeb AnalyticsとかTrackingみたいなカテゴリがあって、それを拒否したらGoogle Analyticsが対象になっていた…みたいな感じなんじゃないかなと。
ネットワークエラーの対応方針
選択的にドメインをブロックしている場合、こちらで対応できることは限られています。ユーザーに「御社のプロキシサーバーの設定を見直してください」とお願いするしかありません。ただ、Google Analyticsが動作することは必須ではないので諦めることとします。
一方で、大量の画像リソースの読み込みが原因でHTTP/2の同時接続数制限に引っかかっている場合は、こちらで対応できることがありそうです。
そもそも大量のリソースを読み込ませること自体があまりよくはありません。が、これは前述した React での実装にこうするときに解決することとしました。それまでにできることとして、キャッシュ設定を見直すこととします。
たとえ数百個のリソースがあったとしても、適切にキャッシュされていれば再度読み込む必要がありません。もしかしたらキャッシュの設定が適切ではなく、高い頻度で再取得をしているのかもしれないと考えました。
調査すると大量の画像リソースは nginx によって配信されていることがわかりました。アプリケーションは Rails で実装しており、静的リソースは Rails のアプリケーションサーバーの負荷を避けるために nginx が直接静的ファイルを読みに行くという構成になっています。
該当する nginx の設定は以下のようになっています。
location ~ ^/images {
root /path/to/app/public;
}
この設定で配信すると、キャッシュコントロール関連のHTTPタグとしては
- Last-Modified: Tue, 04 Feb 2025 03:57:08 GMT
- ETag: W/"67a19014-267"
といったものが付与されていました。
Last-ModifiedとETagの両方を使用している場合、ブラウザはETagを優先して使用します。では、このETagはどのようにして生成されているのでしょうか。これがファイルのハッシュ値などで生成されているのであれば、ファイルの内容が変わらない限りは同じETagが生成され、適切にキャッシュが効いているはずです。
nginxの該当コードが下記です。
etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
r->headers_out.last_modified_time,
r->headers_out.content_length_n)
- etag->value.data;
sprintfで最終更新日時とファイルサイズをハイフンで繋げているだけのようです。おそらく、ファイルのハッシュ値を計算するのはコストが高いのでこのような方法を取っているのでしょう。
Railsアプリケーションはリリースの都度あたらしいアセット一式がサーバー上に配置されるのでリリースの都度最終更新日時が変わってしまいます。このため、リリースの都度クライアント側はアセットが変わっていないのにキャッシュが破棄されることになります。変更されたファイルのキャッシュを確実に破棄したい場合はこれでも良いと思いますが、今回のケースでは大量の画像リソースがあるため、キャッシュを効かせることを優先したいです。
そのため、以下のようにキャッシュ関連のヘッダを追加することとし、Last-ModifiedとETagは無効化しました。
location ~ ^/images {
add_header Cache-Control "public, max-age=31536000, immutable";
etag off;
add_header Last-Modified "";
root /home/apps/real_estimator/current/public;
}
Cache-Control "public, max-age=31536000, immutable"; というのは「どこでキャッシュしても良く、キャッシュ生存期間は1年、このレスポンスは不変である」という意味になり、もっとも強いキャッシュ設定になります。
デメリットとしては画像ファイルが更新された場合にもキャッシュを使用してしまうという点が上げられます。ただ、ファイル名が同じ状態で更新されるケースがほとんどないこと、もしそのようなことがあってもファイル名を変更することでキャッシュを使用しないようにできることからそれをエンジニア内部で合意して運用することとしました。
結果
上記の対策を行った後、特定のユーザーからの問い合わせはなくなりました。おそらく対策が功を奏したのではないかと思われますが、厳密に対策の効果であると言い切るのは難しいです。というもにゃもにゃした結果になりましたが、ユーザーにとっては良かったことと思います。
まとめ
発生していた問題は
- ネットワークエラー
- 社内プロキシサーバーからのTCP RESET
- 社内プロキシサーバーの同時接続数制限によるHTTP/2 REFUSED_STREAM
- Google Maps APIの非同期読み込みによる実行順序の問題
という2つの問題でした。1. に関してはnginxのキャッシュコントロール関連設定を見直すことで、事象が発生する条件を緩和しました。2. に関しては、Google Maps APIの読み込み完了を待つコードを実装することで、非同期読み込みによる実行順序の問題を解決しました。これらの対策を最小の手間で行い、のちの根本解決までの応急的なパッチとして適切な対応が出来たのではないかと思います。
特定のユーザー・環境でだけ発生する再現性の低い問題であっても「おま環」で終わらせず、直すべきところは直し、ユーザーにとって良い結果につなげられたと思われます。
ちょっと精神論じみてしまうかもしれませんが、私はトラブルが起きたときは可能な限り事象を明確にすべきだと思っています。追える情報は時間が許す限りは追うべきと考えます。それが正確な状況把握と問題解決に至るだけでなく、エンジニア自信の成長にもつながるからです。具体的には、状況に応じて以下のようなことを行います。
- ログを全部見る
- curlコマンドで生のHTTPリクエストを正確に生成してAPIを直接叩く
- ブラウザのデベロッパーツールで生のネットワークアクセスを見る
- デバッガがアタッチできるときは内部状態を調べる
- プロファイラーで実行時間、順序、消費リソースを確認する
- ドキュメントを読む
- RFCを読む
- 使用しているOSSのコードを読み解く
- tcpdumpやWiresharkなどでパケットを見る
- TCPの状態遷移図とにらめっこする
Cで書かれたOSSのコードを読み解いたりパケットキャプチャのダンプを見たりというのはハードルが高いと思いますが、一度でもやってみると次からは「まあ最悪パケットのダンプを見ればわかるか」「最悪○○のソースを読み込めば分かるか」という謎の自信が得られるので良いと思います。
スマサテではエンジニアを募集しています。興味がある方はWantedlyのページをご覧ください。
Discussion