はじめに
こんにちは。ソウゾウのSoftware Engineerの @fuku です。
「メルカリShops [フライング] アドベントカレンダー2022」の6日目を担当します。
現在私はメルカリShopsにおける表示速度関連のパフォーマンス改善に取り組んでおり、インフラ、バックエンド、フロントエンドや計測方法構築など多岐に渡る領域に対してアプローチする事になりました。本記事ではメルカリShopsに対して行ったパフォーマンス改善の内容と、その結果について紹介します。
記事のポイント
この記事を読む上で重視して頂きたい点は以下の通りです。
- 表示速度などユーザー体験に関するサービス運用の変化にも注意を向けることが最初の一歩
- 計測グラフを用意するなど可視化する事が必要
- 可視化したらチームにも共有し改善案を一緒に検討しよう
- 速度面のパフォーマンス改善には複数のアーキテクチャ領域を俯瞰しつつ総合的にボトルネックが何処か考えていく必要が有る
- 通常の機能リリースを含め結果測定をしつつパフォーマンス面でも継続的な改善を行うとより良いサービス提供が可能となる
取り組みの始まり
今回の取り組みは、Search Console内のレポートを確認している時に、メルカリShopsの商品ページにおけるCore Web VitalsのLCPスコアが悪化している事に気付いた事が始まりとなりました。他のCore Web Vitalsの指標であるFIDやCLSに関しては問題無いが、コンテンツの読み込み速度指標であるLCPに関しては要改善状態(最大コンテンツ読み込みまで推奨値である2.5秒を超えている)と判定されていました。
メルカリShopsにおいて商品ページは登録商品の数だけURLが存在しており、サイトに占めるページ数の割合としては圧倒的に多くなっています。よって下図に表示されているサイトのページエクスペリエンスが良好(Core Web Vitals指標全てに合格している)と判定されているページの割合が大きく下がってしまいました。
更にアプリやWebにて商品ページを閲覧してみると体感的にも明らかに以前より表示速度が遅く感じたため、ユーザー体験的にも良くない状況となっていそうでした。
表示速度の可視化
表示速度が悪化している可能性は高い状態でしたが、それを客観的に判断出来る様な指標が他に存在していませんでした。先ずはエンジニア間で問題点の共有が出来る状態にした後に、具体的な改善議論を進める必要があると考えました。
メルカリグループでは全社的にBQ(Big Query)に各種ログが集約されており、情報読み込み時のレイテンシーを含んだ情報がBQに格納されています。問題をわかりやすく可視化する為にLooker Studioを用いてグラフを作成する事にしました。
例として以下の様なグラフを作成しました。(前提となるメルカリShopsのアーキテクチャは "メルカリShops の技術スタックと、その選定理由" を参照)
- CDN(fastly)やCloud Run(Next.js)の日別、時間別のレイテンシー推移
- GraphQLや主要Microserviceの日別レイテンシー推移
- CDNへのリクエスト数やキャッシュHit率の日別推移
このグラフを資料として共有しエンジニアチームの全体MTGで明確に速度面が悪化している事を前提に改善相談を行いました。これによりその後の具体的な改善対応へと進む事が出来ました。
メルカリShopsのアーキテクチャ要素
Web版のメルカリShopsはアプリ(WebView)と共通で利用されており、Webの表示速度パフォーマンスがそのままアプリでのパフォーマンスにも影響します。
更にアーキテクチャとして以下の様な全体像を意識しつつボトルネックを解消していく必要があります。
アーキテクチャ全体概要図(情報返却時に関係する項目)
先ずはデータベースなど情報の保存元に近い方から改善すべきとの判断からインフラ、バックエンド領域を対象にボトルネックを調査しつつ、CDNが情報を返却する所(図の赤色の箇所)までの速度パフォーマンスを改善していく事にしました。
インフラ、バックエンドの改善
インフラ、バックエンドの改善について、具体的には以下のような取り組みを実施しました。
Cloud Run(Next.js)の最小インスタンス数の増加
エンジニアチームへの計測グラフ共有が契機となってCloud Run(Next.js)のCPU負荷が以前よりも増加気味という情報を提供してもらいました。Cloud Runは負荷上昇に応じてスケールアウトしますが、常時起動する最小インスタンス数を設定する事も可能なため、最小インスタンス数を増加させ処理速度の向上を目指す事にしました。結果としてCloud Run(Next.js)のレイテンシーが改善し、その影響を受けたCDNのレイテンシーも改善しました。
CDN(fastly)キャッシュ保持期限の延長
こちらの記事 "メルカリShops のフロントエンド" にも説明がありますが、高速に情報を返却する為にHTML情報等のキャッシュがCDNに一定期間存在しています。しかしCDNのキャッシュHit率を計測するグラフからHit率の数値が思ったより低い事に気付きました。商品ページは総数が多くロングテール的な状況にならざるを得ないとはいえキャッシュHit率を向上させる事は表示速度向上にも貢献しそうに思えました。実装工数も効率的な範囲で改善出来る方法としてCDNキャッシュの保持期限を延長する事にしました。
以下のキャッシュHit率を表すグラフを見ても対応後は明らかに数値が改善しました。
その他改善
他プロジェクトとしてML(Machine Learning)やSREを担当するエンジニアが推進していた速度改善対応に関しても計測グラフを通じて明確に把握する事が出来ました。
下記の対応は関連するMicroserviceの処理になりますがGraphQLを通じてNext.jsでのSSR時に同期的に呼び出される為に最終的なレイテンシーに関わってきます。
- MLを使ったおすすめ商品取得の高速化
- ユーザーID関連の変換処理の高速化
各対応を経たCDNの情報返却レイテンシーグラフの推移は以下の様になっており、最も悪化していた時期よりも改善が見られます。
フロントエンドの改善
インフラ、バックエンドに続きフロントエンド側の改善にも取り組みました。
画像読み込みの非同期化
メルカリShopsの商品ページでは複数の商品画像の全てを同期的に読み込む処理となっていましたが、デザイン的にもファーストビューとしても1枚目の画像以外は同期的に読み込む必要は無いので非同期化する事にしました。
実装的に2枚目以降の画像にはlazyローディングを設定しています。
<img src="image.jpg" loading="lazy" />
これによりページの初期読み込み負荷の減少を狙いました。
最大コンテンツの軽量化
現在の所、LighthouseやPageSpeed Insightsで商品ページを測定すると最大コンテンツ(Largest Content)判定されているのはページ上部のSVG画像のバナーでした。svgoを用いて画像ファイルの軽量化を実施した結果、画像の読み込み容量が約30%削減できました。
最大コンテンツのpreload指定
最大コンテンツ判定されている画像をpreload指定する事により優先的に読み込む処理を入れる事にしました。
Chrome DevToolsで確認した所、以下の様にネットワーク的にもpreload指定リソースが優先的に読み込まれLCPが改善している事が確認出来ました。
preload指定無し | preload指定有り |
---|---|
フロントエンド対応の結果は若干改善というレベルに留まりました。この計測には5日目の記事 "メルカリShopsフロントエンドのパフォーマンスを可視化する" でも紹介されたCore Web Vitalsの実測値グラフが大変役立ちました。
改善状況まとめ
ここまでの改善対応でアプリやWebでの体感的な表示速度は、悪化していた時期に比べ速くなったと言える状態になりました。更にCore Web VitalsのLCP実測値やインフラ、バックエンドのレイテンシー計測結果も含めて考えると明らかな改善が見受けられます。しかしページエクスペリエンスのLCPスコアに関しては判定期間が必要な事も影響していそうですが、まだ合格ラインに達していません。
引き続き考えられる改善案としてCDNキャッシュ期限の追加調整、フロントエンド(ブラウザ処理)部分の高速化対応の更なる適用、バックエンドMicroserviceの処理やインフラスペック見直しなど、対策出来そうな事はまだ残っているため、今後も検討を進めるつもりです。
おわりに
一般論としてWebサービス提供開始直後には問題が無くとも機能追加や保持データ量の増加に伴って徐々に速度面などが悪化していく傾向があります。メルカリShopsもサービススタートから約1年が経過しパフォーマンスが徐々に悪化している部分が目立ってきたのかもしれません。
この様なケースでは計測グラフなどを用意しエンジニアチーム全体で活用して早期に問題に気付く事や原因分析をしていく事が大切です。
LCPなどの指標を参考にパフォーマンス改善を実施し、問題点やボトルネックとなる部分の理解を深めるのはサービス運用改善の良いアプローチになると感じています。そしてその表示速度改善の結果がユーザー体験の向上にも繋がっていく事になるため、今後もパフォーマンス改善を行っていきたいと考えています。
株式会社ソウゾウではメンバーを募集中です。メルカリShopsの開発やソウゾウに興味を持った方がいればぜひご応募お待ちしています。
詳しくは以下のページをご覧ください。
Software Engineer
Software Engineer, Site Reliability
Software Engineer (Internship) – Mercari Group (※新卒採用に応募するにはまずインターンへの参加をお願いしています。)
またカジュアルに話だけ聞いてみたい、といった方も大歓迎です。こちら の申し込みフォームよりぜひご連絡ください!