Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /var/www/staging_ichizoku.demowpsites2.com/wp-includes/functions.php on line 6121
【Sentry】TTFB(Time to First Byte)を減らし、ユーザ体験を改善する手法について – Ichizoku

Ichizoku is an official partner of Arize in Japan

【Sentry】TTFB(Time to First Byte)を減らし、ユーザ体験を改善する手法について

最近、私はただひとつの指標、TTFB(Time to First Byte)を改善することに集中することで、すべてのホームページのCore Web Vitalsを改善しました。

データを取得する方法に2つの小さな変更を加えるだけで、p75のTTFBを3.46秒から704msに短縮することができました!
(「p75」と「TTFB」については後述します)

この記事では、私がどのように問題を発見し、それを解決するために何をしたのか。
そして、その過程で下した重要な決断について説明します。

Sentryパフォーマンス・モニタリングの使用

新しいサイトを立ち上げるとき、新機能を開発するとき、サイトが本当に遅いと気づいたときがありました。

2021年から22年にかけて、私はパフォーマンスを改善するためにWebサイトを一から作り直しました。
しかし時間が経つにつれ、私はサイトのさまざまな部分に実験的な技術をたくさん追加し、パフォーマンスが再び、恥ずかしくなるほど悪くなってしまいました。

ここ数ヶ月の間、Webサイトをロードしているときに私自身がこのことに気づいていましたが、Sentryパフォーマンス・モニタリングをサイトに追加したときに初めて全体像を見ることができました。

Sentryのようなパフォーマンス監視ツールを使用することの素晴らしい点は、OS、ブラウザ、モバイルデバイス、インターネット接続、その他ユーザーエクスペリエンスに影響を与える多くの要因すべてにわたって、Webサイトの実際のユーザーデータを表示してくれることです。
以前は、Google Lighthouseのようなツールを開発中やWebサイト構築中に使用して、新しいビルドごとにパフォーマンスを分析していました。実際のユーザーデータの方がはるかに価値があります。

Here’s what the performance looked like on my homepage before any modifications from February 14-21 2024.

2024年2月14日から21日まで、修正前の私のホームページのパフォーマンスはこんな感じでした。

最も緊急に改善すべきと目立ったのは、TTFB(Time to First Byte)でした。
TTFBとは、ブラウザがサーバーにリクエストをしてから、最初の1バイトのレスポンスを受け取るまでの時間を指します。
理論的には、TTFBが低ければ低いほど、ブラウザはより早くページの描画を開始することができ、ユーザーはより早くブラウザで何かを見ることができます。
結果的に、離脱する可能性が低くなります!

ここに表示されているTTFBの値は、75パーセンタイル(p75)のもので、3.46秒が全ホームページビューの75%に見られた最悪のスコアであることを意味します。
これはまた、25%のユーザーがページの読み込みに3.46秒以上待たされたことを意味します。
この悪いスコアは、レスポンスが送り返される前にサーバーで行われている処理が多すぎることを示していました。

ひとつはニュースレター・プロバイダからデータを取得して最新の購読者数を取得するもので、もうひとつはTwitch APIからデータを取得して最新のストリーム動画や現在進行中のライブ・ストリームの最新のサムネイルを表示するものです。

どちらの関数も、最初のHTTPレスポンスをメモリに取り込み、サードパーティのAPIからデータを取得し、それに応じてHTMLを書き換えます。

このアーキテクチャの目的は、静的に生成されたホームページに動的なデータを表示するために、メインのJavaScriptスレッドをブロックする可能性のあるクライアント側のデータ・フェッチを最小限に抑えることでした(スケルトン・ローダーは嫌いです)。

これは 「ユーザーに最新のものを見せる 」という観点では素晴らしいものでした。
しかし、HTTPリクエストが事実上重複してしまうため、ブラウザに何かを表示するのにかかる時間が2倍になってしまうことが問題でした。

そして静的な地域にある2つの別々のサードパーティ・サービスが、世界のどこからでも(エッジから)呼び出されることによるAPIの待ち時間の変化も加わり、ちょっとした混乱に陥り始めます。

正確なニュースレター購読者数は、私以外の誰が求めているのでしょうか?
そして、なぜランダムに生成される最新のストリームのサムネイルを表示する必要があったのでしょうか?

人々は私のホームページの前に座って、数分ごとに更新されるTwitchのサムネイルを見るためにホームページを更新しているわけではありません。私はやりすぎたのです。

データが近似することに問題なし

この時、私が優先したのは、TTFBの改善でした。
最初のステップは簡単で、ニュースレターの購読者数をフェッチするエッジ関数を削除し、代わりにビルド時にデータをフェッチして静的に生成することでした。

ビルド時にAPIコールがエラーになった場合は、数値にプラス記号を追加したり、近似値の文字列を返したりすることで、小さな不正確さを考慮することができます。

ミドルウェアチェーンからEdge Functionを1つ削除しただけで、p75のTTFBが大幅に改善しました。
このたった1つの変更を1週間監視したところ、TTFBのp75値は3.46秒からわずか1.88秒に減少しました。

これは、75%のユーザーがブラウザで私のホームページの何かを見るのにかかった時間を46%短縮したことになります。
ひとつの小さな変更で、すべてのCore Web Vitalsのスコアも向上しました。

データ取得をサーバーからクライアントに変更することの問題点

次のステップは、Twitchのデータを取得するEdge Functionを削除することでした。私の仮説では、この機能をクライアントに移し、準備ができたらデータをDOMに書き込むことで、たとえデータがまだすべて揃っていなかったとしても、ユーザーが感じるページのパフォーマンスが向上すると考えていました。
ミドルウェアがHTTPリクエストをインターセプトしなければ、TTFBは減少し、ユーザーはより早くブラウザで何かを見ることができます。

まず、Twitchのデータ取得をサーバーからクライアントサイドのウェブワーカーに移し、メインスレッドで新たなレンダーブロック動作が発生しないようにしました。しかし、TTFBは確かに減少したものの、累積レイアウトシフト(CLS)が問題になった。(JavaScriptを非同期遅延スクリプトとしてロードすることもできましたが、視覚的な結果は同じでした)。

サイトのパフォーマンスを改善する際、特にCore Web Vitalsに関しては、常にトレードオフが発生します。
ある指標を改善した場合、別の指標のスコアが悪化するかもしれません。
ページが読み込まれた後にデータをフェッチしてDOMを更新すると、私の開発環境ではTwitchストリームのサムネイルが読み込まれるのが最大で1秒遅くなり、ページのコンテンツがずれる原因になりました。
これは、実際のユーザーにとってはさらに長くなる可能性があります。

レイアウトのずれは通常、要素のサイズが最初のHTMLやCSSで定義されていない場合に起こります。これを回避する方法として、同じサイズのプレースホルダー画像(要素で高さと幅が指定されている)を含め、それを後で取得した画像に置き換えるという方法がありますが、私の意見では、これも特に低速のインターネット接続では良い体験ではありません。

この時点で、私はパフォーマンスの問題をひとつサーバーから移し、クライアントに新たなパフォーマンスの問題を作り出した。

Webサイトを可能な限り静的なものにする時が来ました。

TTFB削減のために賢明なトレードオフを行う

2年前に自分のWebサイトを作り直したとき、クライアントサイドのJavaScriptをできるだけ使わない静的なサイトとして構築することを意図的に決定し、サイトのシンプルでナンセンスなデザインもそれを考慮したものでした。

私のWebサイトは常に、私のTwitchストリームのマーケティング・チャンネルとしてデザインされているので、トップページには常にTwitchに関する何かを盛り込みたいと思っています。

2022年に初めてウェブサイトの再構築を開始したとき、ビルド時にフェッチして事前に生成された次の予定ストリームへのリンクを含めました。

私がTwitchでオンまたはオフラインになるたびに、Webフックを使ってサイトを再構築し、新しい情報を更新した。気になる方はどうぞ、 こちらはWebサイト開設当初のスナップショットです。

新しいCLSを導入することなくTTFBを改善するために、私はホームページを再び静的なものにし、私がTwitchに出たりオフラインになったりするたびにWebフック(私のTwitchボット・アプリケーション内)を使って再構築するようにしました。

私がTwitchでライブをしていない場合は、ビルド時に最新のストリームのサムネイルと情報が静的に生成されます。
Twitchでライブ配信している場合は、ここでパフォーマンスのトレードオフが発生します。

リクエスト時にTwitch APIからデータをフェッチして最新のライブ・ストリーム情報を取得する代わりに、Twitchビデオ・プレーヤーの埋め込みを使って現在のライブ・ストリームを表示するようにしました。

この欠点は、プレーヤーを表示するためにページがクライアント側のJavaScriptを余分に読み込むことです。
しかし、私は週に6時間ほどしかライブストリーミングをしていないので、これは良いトレードオフだと思いました。残りの時間は、超高速の静的な体験を得ることができます。

念のため、私のホームページにあるTwitchコンポーネント(静的HTMLをビルドするJavaScript関数です)のコードを簡略化してみました。
isLiveとvodDataパラメータは、ビルド時にTwitch APIから取得されます。

パフォーマンス向上はバランスが大切

最終的には、パフォーマンスを向上させるために、いくつかの妥協をしなければならないかもしれません。
不正確なデータを表示し、週に数時間、余分なJavaScriptをロードすることは許容できると判断することで、私のサイトで最も訪問者の多いホームページのCore Web Vitalsのスコアを大幅に改善しました。

不正確なデータは、すべてのWebサイトやアプリにとって適切ではないかもしれませんが、パフォーマンス向上のバランスを取る際に考慮すべきことです。

私のホームページで動作していたEdge関数を2つとも削除し、完全に静的なビルドに戻したところ、p75のTTFBが80%削減され、わずか704msになりました。

25%のユーザーはまだ704ms以上のTTFBを経験していますが、私のユーザーの75%は704ms未満でページを読み込んでいます。これまでの進歩には本当に満足している。これが静的サイト、ひいては静的サイト・ジェネレーターの輝かしい広告でないとしたら、何がそうなのかわかりません。

例えば、ローカル画像の最適化(avif形式やwebp形式の画像をサポートする場合など)、サードパーティのJavaScriptを静的に読み込むwebringコンポーネントのレンダリング、フォントファイルの最適化(背景テクスチャとして3文字しか使わないように読み込む巨大なファンシーフォントファイルがあるため)、そしておそらくレンダリングをブロックする単一のCSSファイルへの対応などです。

私の親友であるキャシディ・ウィリアムズが言うように、「Webサイトは、追加しすぎて遅くなるまで、速く始まる」です。

 


 

IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。

シェアする

Recent Posts