1. 導入
このセクションは非規範的です。Webアプリケーションのパフォーマンス特性を正確に測定することは、Webアプリケーションを高速化する上で重要な側面です。 [NAVIGATION-TIMING] や [RESOURCE-TIMING] は ドキュメントやそのリソースの詳細なリクエストタイミング情報(リクエスト開始時刻や、接続確立・レスポンス受信に至る様々なマイルストーンなど)を提供します。 しかし、ユーザーエージェントはリクエストのタイミングデータを観測できても、 リクエスト応答サイクルのある段階がなぜどれだけ時間がかかったかについては把握できません―例えば、リクエストがどのようにルーティングされたか、 サーバ上のどこで時間を消費したのかなどです。
本仕様は PerformanceServerTiming
インターフェースを導入します。
これにより、サーバはリクエスト応答サイクルのパフォーマンス指標をユーザーエージェントに伝達でき、アプリケーションはその指標を収集・処理・活用して配信最適化を行うJavaScriptインターフェースを利用できます。
2.
Server-Timingヘッダー・フィールド
Server-Timingヘッダーフィールド は、指定されたリクエスト応答サイクルに関する1つまたは複数の指標と説明の伝達に使われます。 [RFC5234] に基づく Server-Timingヘッダーフィールド のABNF形式は次の通りです:
Server-Timing = #server-timing-metric server-timing-metric = metric-name *( OWS ";" OWS server-timing-param ) metric-name = token server-timing-param = server-timing-param-name OWS "=" OWS server-timing-param-value server-timing-param-name = token server-timing-param-value = token / quoted-string
[RFC7230] の
#, *, OWS, token, quoted-string
の定義も参照してください。
レスポンスには同じ metric-name を持つ server-timing-metric が複数含まれる可能性があり、ユーザーエージェントは全てのエントリを処理・公開しなければなりません。
ユーザーエージェントは、提供された指標を任意の順序で表示してもよく、HTTPヘッダーフィールド内の指標順序は重要ではありません。
このヘッダーフィールドは、将来的なパラメータ追加に対応できる拡張可能な構文として定義されています。レスポンスのServer-Timingヘッダーフィールド内で特定の server-timing-param-name をユーザーエージェントが認識しない場合は、そのトークンを無視して処理を継続し、エラー通知は行いません。
曖昧さを避けるため、各 server-timing-param-name は server-timing-metric
内で複数回出現しないようにするべきです。複数回指定された場合、最初のもののみ考慮され、たとえ server-timing-param
が不完全・不正でも次以降は一切無視し、エラー通知や処理変更もしません。パラメータ順序が重要となる唯一のケースです。
ユーザーエージェントは server-timing-param-value の後、次の server-timing-param や
server-timing-metric の前までに現れる不要な文字を無視しなければなりません。
ユーザーエージェントは metric-name の後、初めの server-timing-param の前や次の
server-timing-metric の前までに現れる不要な文字を無視しなければなりません。
本仕様は server-timing-param-name で "dur" を duration,
"desc" を description
として定義します。どちらもオプションです。
- HTTPオーバーヘッドを最小化するため、指定する名前や説明はできるだけ短く、略語や任意値の省略を推奨します。
- クライアント、サーバ、および中間装置間で時計同期が保証されないため、クライアントタイムライン上で意味のある
startTimeを割り当てることは不可能です。そのため、本仕様ではstartTimeの属性付けを意図的に省略しています。複数エントリ間の関係付けを行いたい場合、開発者はmetric名や説明を使って独自データを伝達できます。 - サーバや中間装置は、どの指標をいつユーザーエージェントに伝達するかを完全に制御できます。例えば、指標へのアクセスをプライバシーやセキュリティ理由で制限することも可能です。詳細は §4 プライバシーとセキュリティ を参照してください。
Server-Timingヘッダーフィールドを解析する 手順:文字列 field を受け取る。
-
position を 位置変数として field の先頭を指す。
-
name を コードポイント列収集で field から U+003B(;) でないものを position指定で取得する。
-
先頭と末尾のASCII空白除去を name に実行。
-
name が空文字列なら null を返す。
-
metric を新しい
PerformanceServerTimingとして生成し、その metric name は name である。 -
params を空の 順序付きマップにする。
-
position が field の末尾でない間:
-
position を1進める。
-
paramName を コードポイント列収集で field から U+003D(=)でないものを position指定で取得。
-
先頭と末尾のASCII空白除去を paramName に実行。
-
position を1進める。
-
paramValue を空文字列にする。
-
ASCII空白スキップを field と position で実行。
-
position の field 内の コードポイント が U+0022(") なら:
-
paramValue を HTTP引用文字列収集(field, position, extract-valueフラグ指定)の結果にする。
-
コードポイント列収集で field から U+003B(;)でないものを position指定で取得。結果は使わない。
-
-
それ以外の場合:
-
rawParamValue を コードポイント列収集で field から U+003B(;)でないものを position指定で取得。
-
paramValue を rawParamValue の先頭末尾ASCII空白除去の結果にする。
-
-
-
metric を返す。
3.
PerformanceServerTiming
インターフェース
[Exposed =(Window ,Worker )]interface {PerformanceServerTiming readonly attribute DOMString name ;readonly attribute DOMHighResTimeStamp duration ;readonly attribute DOMString description ; [Default ]object (); };toJSON
toJSON が呼び出されたら、[WEBIDL] の default toJSON steps を実行する。
3.1. name
属性
name
のゲッター手順は、this の メトリック名 を返すことです。
3.2. duration 属性
duration
のゲッター手順は、次の処理を行います:
-
dur を、this の params[
"dur"] を 浮動小数点数値の解析ルールに従って解析した結果とします。 -
dur がエラーの場合、0 を返し、そうでなければ dur を返します。
duration
は DOMHighResTimeStamp
なので、通常はミリ秒単位の
継続時間 を表します。
実際には強制力はありませんが、duration
は任意の時間単位を表すことができ、ミリ秒単位の
継続時間
を推奨します。
3.3.
description 属性
description
のゲッター手順は、this の
params["desc"] が 存在する場合はそれを返し、なければ空文字を返します。
PerformanceServerTiming
は、空文字で初期化される文字列 メトリック名 を関連付けます。
PerformanceServerTiming
は、初期状態で空の 順序付きマップ params を関連付けます。
3.4. PerformanceResourceTiming
インターフェイスの拡張
PerformanceResourceTiming
インターフェイス(本仕様が一部拡張する)は [RESOURCE-TIMING] で定義されています。
[Exposed =(Window ,Worker )]partial interface PerformanceResourceTiming {readonly attribute FrozenArray <PerformanceServerTiming >serverTiming ; };
3.5.
serverTiming 属性
serverTiming
のゲッター手順は次の通りです:
-
entries を新しい リストとします。
-
各 field を this の timing info の server-timing headers に対して:
-
metric を サーバタイミングヘッダーフィールドの解析 の結果とします。
-
metric が null でなければ、追加 metric を entries にします。
-
-
entries を返します。
4. プライバシーとセキュリティ
このセクションは非規範的です。
本仕様で定義されるインターフェースは、サーバタイミング指標を通知したリソースを組み込んだウェブページに対して、アプリケーションやインフラの秘匿情報を公開する可能性があります。
このため、PerformanceServerTiming インターフェースへのアクセスは既定で 同一オリジンポリシーにより制限されています。
リソース提供者は [RESOURCE-TIMING] で定義された Timing-Allow-Origin
HTTPレスポンスヘッダーを追加することで
サーバ指標へのアクセス許可するドメインを明示的に指定できますが、ユーザーエージェントは引き続き 同一オリジン ポリシー制限を維持してもよいです。
Timing-Allow-Origin HTTPレスポンスヘッダーに加え、サーバは返却する指標の種類・タイミング・対象ユーザーを制御する論理も利用できます。
例えば、正規認証されたユーザーにのみ指標を返し、その他には何も返さないという運用も可能です。
5. IANA考慮事項
永続メッセージヘッダーフィールド登録簿は下記登録に基づき更新されるべきです([RFC3864])。
5.1. Server-Timingヘッダー・フィールド
- ヘッダーフィールド名
- Server-Timing
- 該当プロトコル
- http
- ステータス
- 標準
- 著者/変更管理者
- W3C
- 仕様文書
- 本仕様(Server-Timingヘッダー・フィールド 参照)
6. 例
このセクションは非規範的です。> GET /resource HTTP/1.1 > Host: example.com < HTTP/1.1 200 OK < Server-Timing: miss, db;dur=53, app;dur=47.2 < Server-Timing: customView, dc;desc=atl < Server-Timing: cache;desc="Cache Read";dur=23.2 < Trailer: Server-Timing < (... snip response body ...) < Server-Timing: total;dur=123.4
| 名前 | 時間 | 説明 |
|---|---|---|
| miss | ||
| db | 53 | |
| app | 47.2 | |
| customView | ||
| dc | atl | |
| cache | 23.2 | Cache Read |
| total | 123.4 |
上記ヘッダーフィールドは、サーバがユーザーエージェントへデータ伝達するあらゆるパターン(指標名のみ、値付指標、値+説明付指標、説明付指標)の6つの指標例を示しています。
例えば example.com/resource.jpg の取得の場合:
- キャッシュミスが発生した
- リクエストが "atl" データセンター("dc")経由でルートされた
- データベース("db")処理時間が53msだった
- キャッシュリードは23.2ms
- アプリケーションサーバ("app")による "customView" テンプレートまたは関数処理は47.2ms
- サーバ上のリクエスト応答サイクル全体では123.4msが掛かり、これはレスポンス末尾のトレーラーフィールドで通知される
アプリケーションは提供されたJavaScriptインターフェイスを使って、これらの指標を収集・処理・活用できます:
// serverTiming のエントリは 'navigation' および 'resource' エントリに存在し得ます for ( const entryTypeof [ 'navigation' , 'resource' ]) { for ( const { name: url, serverTiming} of performance. getEntriesByType( entryType)) { // serverTiming 配列を走査 for ( const { name, duration, description} of serverTiming) { // "遅い"ものだけ考慮 if ( duration> 200 ) { console. info( '遅い server-timing エントリ =' , JSON. stringify({ url, entryType, name, duration, description}, null , 2 )) } } } }
7. ユースケース
このセクションは非規範的です。7.1. 開発者ツールでのサーバタイミング
サーバ処理時間は、リクエスト全体の時間の主要な部分を占めることがあります。 例として、動的なレスポンスでは複数回のデータベースクエリやキャッシュ検索、API呼び出し、関連データの処理やレスポンスの描画などが必要となる場合があります。同様に、静的レスポンスであっても、サーバの過負荷やキャッシュの遅延、その他の理由によって遅くなることがあります。
現在、ユーザーエージェントの開発者ツールではリクエスト開始・レスポンスの最初および最後のバイト受信時刻は表示できますが、サーバ内のどこでどう時間を費やしたかの可視性はありません。そのため、開発者はサーバのパフォーマンスボトルネックや構成要素特定が困難です。これを知るには、サーバログの確認、レスポンス内へのパフォーマンスデータ埋め込み(可能なら)、外部ツール利用など異なる手法が必要になり、診断が難しく非実用的な場合も多いです。
Server Timingは、サーバがクライアントへ関連パフォーマンス指標を伝達し、クライアントで開発者ツールへ直接表示する標準機構を定義します―例えばリクエストへサーバ送信指標の注釈を付与することで、レスポンス生成時の時間消費箇所への洞察が得られます。
7.2. 自動分析のためのサーバタイミング
開発者ツールでサーバ送信パフォーマンス指標を表示するだけでなく、標準JavaScriptインターフェースを使うことで分析ツールによる指標の自動収集・処理・ビーコン・集計が可能となり、運用やパフォーマンス分析に役立てられます。
7.3. リクエストルーティングパフォーマンスの測定
Server Timingは、オリジンサーバがリクエスト処理時にどこやどのように時間が消費されたかのパフォーマンス指標を伝達できるようにします。しかし、同じリクエストやレスポンスは複数のプロキシ(例:キャッシュサーバやロードバランサなど)を通じてルーティングされる場合もあり、それぞれが独自の遅延を追加したり、時間の消費箇所や方法についてのパフォーマンス指標を提供したい場合があります。
例えばCDNエッジノードは、利用データセンター、キャッシュ有無、キャッシュやオリジンサーバからのレスポンス取得時間などを報告できます。同様処理が他のプロキシでも繰り返されることで、リクエストルートや時間消費箇所へのエンドツーエンド可視性が得られます。
また、Service Worker が有効な場合、一部または全てのナビゲーションやリソースリクエストは経由されることがあります。Service Workerはローカルプロキシとしてリクエストのリルート、キャッシュレスポンスの提供、レスポンス合成などを実施できます。結果として、Server TimingはService Workerからリクエスト処理方法(サーバ取得・ローカルキャッシュ提供、関連処理ステップの所要時間等)に関するカスタム指標通知を可能にします。
8. 謝辞
このセクションは非規範的です。本文は[NAVIGATION-TIMING]、 [RESOURCE-TIMING]、 [PERFORMANCE-TIMELINE-2]、 [RFC6797] 仕様のライセンス範囲でテキストを再利用しています。