ほとんどの場合に高速であるだけでは不十分で、いつでも高速でなければならないというのが Chrome チームの考えです。今回の「速さと好奇心」の投稿では、ウェブに関する主な指標を向上させ、最終的にウェブのパフォーマンスを改善できた方法について取り上げます。これは、あらゆるウェブサイトでのユーザー インタラクションへの応答を表す Chrome のフィールド データを調査することによって実現しました。
日々、何十億人もの人々がさまざまなことにウェブを活用しています。ブラウザは同時に多くのアプリをホストしなければならなくなり、リソースの競合が課題になっています。マルチプロセス ブラウザである Chrome では、複数のリソースが競合しています。CPU やメモリはもちろんのこと、内部サービス(この記事では、ネットワーク サービス)間の専用作業キューもあります。
このような理由のため、私たちは Chrome ユーザーのフィールド データから遅いインタラクションを特定し、修正することに重点を置いています。このフィールド データこそ、実際のユーザー エクスペリエンスを表す確かな情報源です。このデータは、Chrome Canary 版で匿名化した Perfetto トレースを記録し、プライバシー保護フィルタを使って報告することで収集しています。
遅いインタラクションのフィールド データに注目したとき、ある 1 つの原因が浮かび上がってきました。それは、ネットワーク サービスから現在のサイトの Cookie を取得するため、同期呼び出しを繰り返し行っていることです。
その経緯から振り返ることにしましょう。
進化するウェブにおける Cookie
Cookie は、その創生期のころからウェブ プラットフォームの一部であり続けています。通常は、次のようにして作成します。
document.cookie = "user=Alice;color=blue"
すると、次のようにして取得できます。
// Assuming a `getCookie` helper method:
getCookie("user", document.cookie)
シングルプロセス ブラウザでは、この実装はシンプルで、Cookie の器はメモリに保持されていました。
しかし時間が経つと、ブラウザはマルチプロセスとなり、Cookie の器をホストするプロセスは、ますます多くのクエリに答えなければならなくなります。ただし、ウェブの仕様では、Cookie は Javascript から同期的に取得できなければなりません。そのため、document.cookie
クエリに回答する操作はブロック操作です。
この操作自体は非常に高速なので、通常、このアプローチは問題にはなりませんでした。しかし、高負荷シナリオでは、複数のウェブサイトがネットワーク サービスから Cookie(およびその他のリソース)をリクエストしており、リクエストのキューが滞る可能性があります。
遅いインタラクションのフィールド トレースから、一部のウェブサイトで、Cookie が連続して複数回フェッチされるという非効率的なシナリオが起きていることがわかりました。そこで追加の指標を作成し、すべてのナビゲーションでの冗長な GetCookieString()
IPC(前回と同じ値が返されたもの)の頻度を測定しました。その結果、Cookie アクセスの 87% が冗長で、それが毎秒数百回発生している場合もあることがわかりました。これは驚愕の事実でした。
つまり、document.cookie
のシンプルなデザインが裏目に出たということです。ウェブの JavaScript では、これをローカル値のように扱っていましたが、実際にはリモート検索が行われていました。これは、古典的なコンピュータ サイエンスのキャッシュを行えばよいケースでしょうか?!早まってはいけません!
ウェブの仕様では、協調ドメインが相互に Cookie を変更し合えることになっています。したがって、レンダラ プロセスごとの単純なキャッシュでは、うまくいきません。そのようなサイト間で書き込みが伝播されないからです(古い Cookie が残り、e コマース アプリケーションでカートが同期されなくなるなどの現象が発生します)。
新たなパラダイム : 共有メモリのバージョニング
これを解決したのが、私たちが共有メモリのバージョニングと呼ぶ新たなパラダイムでした。すなわち、document.cookie
のそれぞれの値と、単調に増加するバージョン番号を組み合わせるという考え方です。各レンダラは、最後に読み取った document.cookie
を、バージョン番号とともにキャッシュします。ネットワーク サービスは、そのバージョンのそれぞれの document.cookie
を共有メモリにホストします。このようにすると、レンダラはネットワーク サービスにプロセス間クエリを送信しなくても、最新バージョンを保持しているかどうかがわかります。
この結果、Cookie 関連のプロセス間メッセージが 80% 削減され、document.cookie
へのアクセスが 60% 速くなりました 🥳。
仮説の検証
アルゴリズムを改善するのは良いことですが、私たちが最終的に重視しているのは、改善によって遅いユーザー インタラクションが速くなったかどうかです。つまり、遅い Cookie クエリが遅いインタラクションの主要な原因であるという仮説を検証する必要があります。
これを実現するため、Chrome の A/B テスト フレームワークを使って効果を調査しました。その結果、すべてのプラットフォームで、他の改善によるリソースの競合の減少と合わせて、最も遅いインタラクションを約 5% 改善できたことがわかりました。そして、ウェブに関する主な指標を満たすサイトがさらに増加しています 🥳。こうしたすべてのことにより、ユーザーがさらにシームレスだと感じられるウェブが実現します。
Chrome におけるウェブで最も遅いインタラクションの加重平均のタイムライン。本機能が 1%(11 月)のユーザー、50%(12 月)のユーザー、すべてのユーザー(2 月)にリリースされるにあたっての状況。
シームレスなウェブに向かいましょう!
Posted by Eiji Kitamura - Developer Relations Team