トラス構造が幾何学的に組まれた建築物のファサード
ニュース深掘り

地震早期警報システムに学ぶWebの体感速度を奪う落とし穴

目次を見る

フロントエンドで「読み込みが遅い」と感じさせる原因を、ミリ秒単位で切り分けられているでしょうか。

パフォーマンス改善に取り組むWebエンジニアやSREの方に向けて、レイテンシ予算(各処理工程に割り当てる許容遅延時間)という考え方を整理します。2026年10月17日にパキスタンで観測されたマグニチュード5.7の地震に関する技術解説記事が、早期警報システム(EEW: Earthquake Early Warning)の設計で使われるレイテンシ予算の考え方を紹介していました。これはそのままWebアプリの体感速度設計に転用できる枠組みです。

何が起きるか: 「速い」の内訳が見えていない

EEWシステムでは、震源からP波(初期微動)を検知し、被害をもたらすS波(主要動)が到達する前に警報を出す必要があります。

都市部までの距離が30〜70kmの場合、警報が使える時間はわずか3〜10秒です。この短い時間を、センサー取得・トリガー判定・検証・配信・端末処理という複数の工程に配分し、それぞれに上限時間(レイテンシ予算)を設定します。

Webアプリの表示速度も構造は同じです。「ページが遅い」という一言の裏には、DNS解決・TLSハンドシェイク・サーバー処理・JSバンドルのダウンロードと実行・ハイドレーション(サーバーで生成したHTMLにJSの動作を後付けする処理)など、複数の工程が積み重なっています。

どこか1工程が予算を超過すると、全体の余裕が一気に失われます。EEW解説記事では、各工程の上限を足し合わせても最悪ケースで約1.3秒に収まるよう設計し、残りの余裕を障害対応に回す考え方が示されていました。

なぜ起きるか: 工程ごとの予算を誰も決めていない

この落とし穴の根本原因は、ほとんどのチームが「全体で3秒以内」のような粗い目標しか持っていないことです。

EEWの表では、センサー取得10ms以下、トリガー判定20〜50ms、エッジ検証30〜100ms、警報生成20ms以下、配信100ms〜1秒、端末処理50ms以下、と工程ごとに数値が割り振られていました。

Web版に置き換えると、TTFB(Time to First Byte: サーバーが最初の1バイトを返すまでの時間)、LCP(Largest Contentful Paint: 最大のコンテンツが描画されるまでの時間)、TBT(Total Blocking Time: メインスレッドがブロックされる合計時間)、INP(Interaction to Next Paint: 操作から画面反映までの時間)といった指標がそれぞれの工程に対応します。

ところが多くのプロジェクトでは、Core Web Vitals(Googleが提唱する体感速度の指標群)のLCPだけを見て「2.5秒以内だから合格」と判断し、TBTやINPの内訳を追っていません。これはEEWで言えば「警報が3秒以内に届けばいい」と全体しか見ず、どの工程が時間を食っているか分からない状態と同じです。

さらにEEW記事は、検知感度を上げると誤報が増えるトレードオフにも触れていました。Webでも同様に、計測の精度を上げようとRUM(Real User Monitoring: 実ユーザーの計測データ)のサンプリング率を上げると、計測自体がメインスレッドを圧迫し、INPを悪化させるという本末転倒が起こり得ます。

自分のプロジェクトが該当するか確認する

該当するかどうかは、以下の手順で確認できます。

  • ChromeのDevToolsで「Performance」タブを開き、ページ読み込みを記録して、工程ごとの所要時間が色分け表示されているか確認する
  • npx lighthouse https://対象URL --output=json --output-path=report.json を実行し、LCP・TBT・CLS(Cumulative Layout Shift: レイアウトのずれ)の内訳が別々に出力されているか見る
  • package.jsonの依存関係を確認し、計測ライブラリ(web-vitalsなど)が導入されているか、導入されていればどの指標だけを送信しているかをコードで確認する
  • PageSpeed InsightsでフィールドデータとラボデータがそれぞれLCP・INP・CLSを個別に表示しているか確認する

これらのうち「全体の読み込み時間」しか手元の数値がない場合、工程別のレイテンシ予算が存在しない状態です。改善の優先順位が決められず、場当たり的な最適化を繰り返すことになります。

対策の手順

工程ごとに予算を設定し直す作業は、次の順序で進められます。

# Lighthouse CIで継続計測し、指標ごとに閾値を設定する
npm install -D @lhci/cli
npx lhci autorun --collect.numberOfRuns=3

lighthouserc.jsonでは、assertions内にLCPやTBTの個別閾値を記述できます。

{
  "ci": {
    "assert": {
      "assertions": {
        "largest-contentful-paint": ["error", {"maxNumericValue": 2500}],
        "total-blocking-time": ["error", {"maxNumericValue": 200}],
        "interactive": ["error", {"maxNumericValue": 3800}]
      }
    }
  }
}

このように工程別の上限を設定しておけば、CIでどの工程が予算超過したかが即座に分かります。EEWシステムでウォッチドッグタイマー(異常を検知したら安全側に倒す仕組み)を入れて「検知できなければ警報を出さない」とフェイルセーフに倒すのと同じ発想で、Web側も「閾値を超えたらCIを失敗させる」ルールを先に決めておくことが有効です。

次に、計測の重さ自体を見直します。web-vitalsライブラリは軽量ですが、サードパーティのRUMツールを複数並行導入していると、それ自体がTBTを押し上げます。Chrome DevToolsのPerformanceタブで「Script」区分の割合を確認し、計測スクリプトが全体の何%を占めているか調べてください。

最後に、エッジランタイム(CDNの近接拠点で処理を実行する仕組み)の活用も検討対象になります。Vercel EdgeやCloudflare Workersは、オリジンサーバーまで往復せずユーザーに近い拠点で処理を返すため、EEWにおける「エッジ集約・検証」の役割に近い働きをします。TTFBの短縮が必要な場合、まずどの処理をエッジに移せるか、フレームワークのドキュメント(Next.jsならRuntime設定、NuxtならNitroのプリセット)を確認してみてください。

まとめ

体感速度の改善は、全体の数値を眺めるだけでは手が打てません。

工程ごとにレイテンシ予算を割り振り、どこが超過しているかを特定する発想が欠かせません。

次の一歩として、まずLighthouse CIをプロジェクトに導入し、LCP・TBT・INPそれぞれに閾値を設定してみてください。

計測ツール自体が処理を圧迫していないかも、DevToolsのScript区分で一度確認しておく価値があります。

参考

Engineering Resilient Systems for a Magnitude 5.7 Earthquake in Pakistan

この記事について: 本記事は AI を活用して作成し、forva AI 編集部が内容を確認・監修しています。

AI 駆動開発のご相談は forva AI へ。まずはお気軽にどうぞ。