はじめに
こんにちは。運用支援チームのすかんくです。
今回は「社内では速いのに、社外から Microsoft Entra application proxy(以下 App Proxy)経由だと遅い」という、App Proxy を使っていると一度は言われるやつを、どう切り分けたかというお話です。
先に白状しておくと、この事例の犯人は App Proxy ではありませんでした。ただ、そこに辿り着くまでにやった「ブラウザのネットワークログを2経路で取って差分を見る」「その読み込みを AI に任せる」という手順は、App Proxy に限らず使い回せると思ったので残しておきます。
背景:ある日の問い合わせ
とあるお客様で、オンプレの稟議ワークフローシステムを App Proxy で社外公開していました。そこに来た申告がこちら。
- 社内 LAN からだとサクサクなのに、社外から App Proxy 経由だと「もたつく」
- 混雑する時間帯はタイムアウトしてアクセスできないこともある
この申告については以下の2パターンに分けられそうです。
- App Proxy(の中継)が遅い
- サーバ側が遅いのだが、社外ユーザーは App Proxy 経由でしかアクセスしないので「App Proxy 経由のときだけ遅い」ように見える
対策は正反対(コネクタや経路を見直すか、サーバ側を見直すか)なので、まずは切り分けをします。
App Proxy の通信経路と遅延が乗る場所
App Proxy 経由の通信は、ざっくり3ホップで構成されています。
- ユーザー → App Proxy サービス(Azure 上の公開エンドポイント)
- App Proxy サービス → プライベート ネットワーク コネクタ(コネクタからのアウトバウンド接続)
- コネクタ → 社内のアプリケーション
それぞれに足される遅延の種類が違います。
| ホップ | 主に足されるもの |
|---|---|
| 1 | ユーザーの回線品質(モバイル回線など)、App Proxy サービス インスタンスのリージョンまでの距離 |
| 2 | コネクタからの Azure 向け経路、コネクタ サーバの負荷、(あれば)TLS インスペクション |
| 3 | コネクタとアプリの距離、KCD 利用時のドメイン コントローラー応答、そしてアプリ自身の処理時間 |
Microsoft のドキュメントにも「どのプロキシ/VPN ソリューションでも遅延は必ず追加される」と明記されています。つまり「App Proxy を通すと少し遅くなる」こと自体は仕様で、問題は「どのくらい遅くなるのが正常で、それを超えているのはどこの責任か」です。
切り分けの考え方は「定数」か「比例」か
社内直アクセスと App Proxy 経由で同じ操作をしたときのリクエストごとの差分を眺めると、だいたい次の3パターンに分かれます。
| 差分の性質 | 疑う場所 |
|---|---|
| どのリクエストでもほぼ一定の差分が乗る | 経路の固定コスト(プロキシ中継、回線 RTT) |
| 特定のリクエストだけ大きい、時間帯で変動する | サーバ処理(負荷、DB、特定機能) |
| 受信時間(receive)だけ伸びる、レスポンスサイズと相関する | 帯域(モバイル回線、大きなレスポンス) |
もう一つ大事なのが「リクエスト数」です。1件あたり 100ms 程度の固定遅延でも、画面表示のために直列で数十件のリクエストが走るアプリ(ワークフロー系にはよくある)だと、合算で数秒の差になります。「1件の数値は問題ないのに、ユーザーは遅いと言う」というギャップは、ここで説明できることも多いです。(要は利用体験全体で観測をする必要がある)
測定設計としては最低3経路
ログを取る前に、経路と時間帯を決めておきます。今回反省した点も含めて、おすすめは以下です。
| 経路 | 含まれる要因 | 役割 |
|---|---|---|
| 社内 LAN → 直アクセス | アプリのみ | 基準 |
| 社外回線 → VPN → 直アクセス | 回線 + アプリ | 回線要因の対照 |
| 社外回線(同じ回線)→ App Proxy 経由 | 回線 + App Proxy + アプリ | 申告と同じ経路 |
| 社内 LAN → App Proxy の外部 URL | App Proxy + アプリ | App Proxy 要因のみ |
今回は上から1番目と3番目しか取れておらず、後述の通り「モバイル回線の分」と「App Proxy の分」が分離できませんでした。可能なら2番目か4番目のどちらかは追加したいところです。
時間帯は「問題が出ている時間帯」と「空いている時間帯」の2つ。加えて、ログと同時刻のサーバ側メトリクス(CPU、メモリ、IIS ログなど)を必ず突き合わせてください。ここが無いと、サーバ側の変動成分はどう頑張っても評価できません。
ログの取り方
Chrome / Edge の開発者ツール(F12)→ Network タブで取得します。
- 「Preserve log」を有効化、必要なら「Disable cache」も有効化
- 申告と同じ操作(ログイン → 一覧表示 → 詳細表示、など)を実施
- 右クリック → 「Save all as HAR with content」でエクスポート
chrome://net-export の netlog でも取れますが、HAR のほうがリクエスト単位で timings(blocked / dns / connect / ssl / send / wait / receive)が揃っていて、後で AI に読ませやすいです。
ログのファイル名には経路と時刻を入れておくとAI に渡すときの説明が楽になります。
(例:internal_direct_0900.json、external_appproxy_0900.json など)
AI にネットワークログを読ませる
ここからが本題です。HAR を目視で読むのは数十件を超えたあたりで心が折れるので、AI に読ませます。ただし生ログを放り込んで「遅い原因を教えて」と聞くと、それっぽい一般論が返ってくるだけです。前章の判定ロジック(定数か、比例か、帯域か)をそのまま観点として渡します。
実際に使ったプロンプトを、汎用化して載せておきます。
(専門家ではないので、より重視すべき分析観点があればこっそりお知らせください)
あなたは Web アプリのパフォーマンス分析者です。
添付の JSON は、同じオンプレ Web アプリに対して同じ操作を行ったブラウザのネットワークログ(HAR から抽出)です。
ファイル:
- internal_direct_0900.json : 社内LANから直アクセス(基準)
- external_appproxy_0900.json : 社外回線から Microsoft Entra application proxy 経由
※0900は取得時刻、1300パターンもあります。
目的:
「App Proxy 経由のときだけ遅い」という申告について、遅延が
(a) 経路の固定コスト(プロキシ中継・回線RTT)
(b) サーバ処理時間(負荷・特定機能)
(c) 帯域・レスポンスサイズ
のどれに由来するかを、ログから言える範囲で判定してください。
手順:
1. 除外: host が login.microsoftonline.com / *.msauth.net / *.msftauth.net / aadcdn.* の
認証系エントリ、status 302/304、fromCache=true のエントリは集計から除外し、除外件数を報告する。
2. 対象アプリのホスト(社内URLと *.msappproxy.net または独自ドメイン)だけを残し、
URL のパスをキーに両ファイルのエントリを突き合わせる。突き合わせできなかった件数も報告する。
3. 指標: timings.wait(TTFB相当)、timings.receive、time(総時間)、connect+ssl について、
ファイルごとに件数・中央値・平均・p95 を表にする。平均だけで結論を出さない。
4. 差分の性質判定:
- パスごとの wait の差分(external − internal)を計算し、その分布(中央値、IQR)を示す。
差分がほぼ一定なら (a)、特定パスだけ大きい/分散が大きいなら (b) の疑い。
- receive の差分が大きく bodySize と相関するなら (c) の疑い。
- connect/ssl の差分は接続確立コストとして別に報告する。
5. リクエスト構造: 主要な画面遷移について、直列に依存しているリクエスト数
(前のレスポンス完了後に開始しているもの)を数え、「1件あたりの差分 × 直列件数」で体感への影響を見積もる。
6. 異常検知: status 5xx、time > 10s、同一パスの再試行、App Proxy のエラー応答を列挙する。
7. 断定できない点は「不明」とし、必要な追加データを箇条書きで挙げる。
出力形式:
- 概要(3行以内)
- 表1: 除外・突き合わせ件数
- 表2: 経路別の統計(wait / receive / time / connect+ssl)
- 表3: パス別差分トップ10(wait 差分の大きい順)
- 判定: (a)/(b)/(c) の寄与の見立てと根拠
- 直列リクエスト数と体感影響の見積もり
- 異常・エラー一覧
- 追加で取得すべきデータ意識したポイントは以下の3点です。
- 除外条件を明示する
- 認証リダイレクト(login.microsoftonline.com)が混ざると、App Proxy 側の wait が跳ねて見えます
- 本当はApplication Proxy側の構成で事前認証を無しとしておきたいのですが、お客様本番環境であるため今回は断念
- 平均だけで語らせない
- 中央値と p95、差分の分散まで出させると「一定かどうか」が数字で見えます
- 「不明」と言える余地を残す
- ここを塞ぐと AI は必ず何か言い切ってしまうので、意図的に言い訳の余地を残す
(返ってきた結果に対して、除外前後の件数が HAR の entries 数と合っているか、認証系ホストが本当に消えているか、くらいは人間側で確認しておくと安心です)
実際にやってみた結果
社内 LAN → 直アクセス、社外(テザリング)→ App Proxy 経由の2経路を、9:00 と 13:00 に取得しました。集計結果を丸めたものがこちらです。
| 経路 | 時間帯 | wait(TTFB相当)中央値 | 総時間 中央値 |
|---|---|---|---|
| 社内 → 直アクセス | 9:00 | 約 24 ms | 約 31 ms |
| 社外 → App Proxy | 9:00 | 約 148 ms | 約 156 ms |
| 社内 → 直アクセス | 13:00 | 約 22 ms | 約 30 ms |
| 社外 → App Proxy | 13:00 | 約 152 ms | 約 161 ms |
差分は2時点とも約 125〜130 ms で、パスによる差もほとんどありませんでした。
つまりこのログの範囲では「定数成分が支配的」で、サーバ処理の変動成分はほぼ見えていません。
言えること
- App Proxy 経由のアクセスには、直アクセスに対して約 130 ms の固定的な上乗せがある
- 150 ms 前後の TTFB は、公開 Web の一般的な基準(web.dev では 800 ms 以下が「良好」)で見れば十分速い
- この基準が今回のサービスに対して適用されるべきかは自信がありませんが
- ただし社内ユーザーは 20 ms 台の応答を「普通」として体感しているので、相対的には約 6〜7 倍。「もたつく」という申告自体は正当
- 一方で、156-160ms程度の遅延で「もたつく」という表現をするかと言われると、個人的な感覚では否
言えないこと
- 約 130 ms のうち、モバイル回線の RTT と App Proxy 中継の内訳
- 社外側がテザリングだったので分離できていません(前述の測定設計の反省点)
- 問題が出ている時間帯のサーバ側の挙動
- 取得した時間帯にはタイムアウト級の遅延は出ておらず、サーバ側メトリクスも未取得でした
- マネージドサービス上でホストされており、業者とのコミュニケーション都合により断念
なので、この時点の報告は「App Proxy の固定コストは把握できたが、申告の主因がどちらかは断定できない。問題発生時刻のログとサーバ側メトリクスをいただければ結論が出そうです」で止めました。
対応としては中途半端だと自分でも感じますが、Entra側のサインインログの数と照らし合わせても、利用状況から App Proxy が原因となるとは思えず、過去の経験を信じてこの段階でコネクタ増設やリージョン最適化に走らなかったのは正解だったと考えています。
結末:決め手は「障害中に直アクセスしてみた」だった
その後の定例で、お客様側から決定的な情報が出てきました。
「昨日は遅すぎてアクセス不能になった。直アクセスならかろうじて繋がった」
App Proxy を通さなくても瀕死なら、主因はサーバ側です。約 130 ms の固定コストは、瀕死のサーバの応答にさらに上乗せされて「タイムアウト」として顕在化していただけでした。
結論として「App Proxy 起因ではなくホストサーバ側」と整理され、サーバリプレースの動作検証で改めて確認いただくとして本件はクローズしました。
身も蓋もない話ですが、「問題が起きている最中に、プロキシを外した経路で試す」だけで切り分けの半分は終わります。ログ分析はそれを裏付け、かつ「正常時のベースラインはこのくらい」という基準を残すためのものだと割り切るのがよさそうです。(今回は顧客環境でこちら主導で試すことが困難な状況にあったため、ログベースでの対応をした)
別の観点では、リプレース後に「App Proxy 経由で 150 ms 前後なら正常」と言える根拠が残ったことは、今後のパフォーマンス評価において地味に価値がありました。
App Proxy 側で併せて確認しておきたいこと
今回は出番がありませんでしたが、差分が「一定」で、かつその値が大きすぎる(数百 ms 以上)場合は、App Proxy 側の構成を疑う番です。チェックリストとして置いておきます。
| チェック項目 | 目的(何を疑う/確認する) | 確認内容(要点) |
|---|---|---|
| コネクタ グループのリージョン最適化 | 無駄なリージョン越えによる固定遅延を減らす | テナントのリージョンとコネクタ配置がズレていないか/コネクタ 1.5.1975.0 以降ならコネクタ グループに近いリージョン指定が可能 |
| コネクタの配置 | コネクタ〜アプリ間の遅延/不安定さを減らす | アプリと同一ネットワーク セグメントに置く/1グループに 2〜3 台を目安に冗長化 |
| コネクタ サーバのリソース | コネクタ自体の処理詰まりを避ける | CPU・メモリ使用率を 70% 未満に保つ/Perfmon のコネクタ用カウンターで監視 |
| コネクタ サーバの HTTP/2 | 既知の挙動差/問題要因を潰す | Windows Server 2019 以降は WinHttp の HTTP/2 を無効化しておく必要があるケースがある |
| コネクタ〜Azure 間の TLS インスペクション | TLS 中間者での劣化/不具合を避ける | 原則やらない(通信不成立や性能劣化要因になりうる) |
| KCD(Kerberos 制約付き委任)利用時 | 認証周りの遅延が支配していないか確認 | ドメイン コントローラーの応答性(遅延/負荷/ネットワーク到達性) |
| バックエンド アプリケーション タイムアウト | 長時間処理のタイムアウトを防ぐ | Default(85秒)で足りない処理があるなら Long(180秒)を検討 |
| コネクタのイベント ログ/診断ツール | 原因の手がかりを取る | Admin / Session ログを確認/Connector Diagnostics tool を利用 |
レスポンス ヘッダ x-ms-proxy-service-name | どのサービス インスタンス経由か特定 | 実際にどのサービス インスタンスを経由したかを把握する(切り分け・相関取りに有用) |
おわりに
今回は App Proxy が「遅い」と言われたらどんな調査が出来るか、というお話でした。
少しでも参考になれば嬉しいです。ではまた!