Save 37% off PRO during our Black Friday Sale! »

70万通りのURLを持つWebサービスを Next.jsにリプレイスして高速化した話

70万通りのURLを持つWebサービスを Next.jsにリプレイスして高速化した話

ジャムジャム!!Jamstack_2に登壇した際の発表資料です。
https://jamjamjamstack.connpass.com/event/226467/

ご質問あれば、Twitter: aiji42_dev までどうぞ。

56f81d479d44a1e00a577424bb45fd4a?s=128

AijiUejima

October 28, 2021
Tweet

Transcript

  1. 0 ジャムジャム!!Jamstack_2 70万通りのURLを持つWebサービスを Next.jsにリプレイスして⾼速化した話

  2. 1 © 2021 Ateam Inc. 1 Uejima Aiji リードエンジニア@株式会社エイチームライフスタイル Twitter:

    aiji42_dev 8年のキャリアの中で、フロントエンジニアよりも バックエンドエンジニアとしてのキャリアのほうが長い (3:7くらい) でも最近はフロントエンドがメイン
  3. 2 © 2021 Ateam Inc. 2 今日はURLが膨大なサービスに Next.jsを導入した際の

  4. 3 © 2021 Ateam Inc. 3 立ちはだかった壁と その乗り越え方を紹介します

  5. 4 © 2021 Ateam Inc. 4 題材となるサービス

  6. 5 © 2021 Ateam Inc. 5 ライフエンディングに関する情報サイト 自分や家族にぴったりのお墓・霊園を探し、 資料請求をするサービス

  7. 6 © 2021 Ateam Inc. 6 トップ 記事 霊園詳細 1K

    Pages 700K Pages 30K Pages エントリー 霊園リスト&検索
  8. 7 © 2021 Ateam Inc. 7 トップ 記事 霊園リスト&検索 霊園詳細

    1K Pages 700K Pages 30K Pages エントリー エリア(市区町村・駅)x霊園特徴(樹木葬, 納骨堂...etc.)
  9. 8 © 2021 Ateam Inc. 8 もともとはパフォーマンスが非常に悪かった

  10. 9 © 2021 Ateam Inc. 9 引用: https://addyosmani.com/blog/web-vitals-extension/

  11. 10 © 2021 Ateam Inc. 10 LCP (Largest Contentful Paint)

    CLS (Cumulative Layout Shift)
  12. 11 © 2021 Ateam Inc. 11 2020年 CoreWebVitalsをSEO評価に導入するとのアナウンスがあった https://developers.google.com/search/blog/2020/11/timing-for-page-experience

  13. 12 © 2021 Ateam Inc. 12 手を打つ必要があるということで

  14. 13 © 2021 Ateam Inc. 13 Next.jsを用いたJamstack化による CoreWebVitalsの改善を行った

  15. 14 © 2021 Ateam Inc. 14 その結果 大幅なパフォーマンス改善に成功!

  16. 15 © 2021 Ateam Inc. 15 LCP CLS

  17. 16 © 2021 Ateam Inc. 16 本題に入る前に

  18. 17 © 2021 Ateam Inc. 17 SSR / SG /

    ISR
  19. 18 © 2021 Ateam Inc. 18 この3つの用語を居酒屋を例にしておさらい

  20. 19 © 2021 Ateam Inc. 19 SSR (Server Side Rendering)

  21. 20 © 2021 Ateam Inc. 20 注文を受けて、 その都度ドリンクを注いで提供

  22. 21 © 2021 Ateam Inc. 21 時間はかかるがキンキンに冷えている (リアルタイム志向)

  23. 22 © 2021 Ateam Inc. 22 SG (Static Generate) (少し前まで

    SSG と呼ばれていた)
  24. 23 © 2021 Ateam Inc. 23 開店前にドリンクを作り置きしておく

  25. 24 © 2021 Ateam Inc. 24 提供は爆速 しかし鮮度は保証できない ※注文が入ってもストックの数は減らない

  26. 25 © 2021 Ateam Inc. 25 ISR (Incremental Static Regenerate)

  27. 26 © 2021 Ateam Inc. 26 作り置きするのはSGと同じ ドリンクを提供した際に 鮮度が落ちていたら次の注文に備えて作り直す

  28. 27 © 2021 Ateam Inc. 27 提供は爆速 注文頻度の高いメニューは鮮度良

  29. 28 © 2021 Ateam Inc. 28 今日お話するライフドットではISRを採用しています そしてVercelにデプロイしています

  30. 29 © 2021 Ateam Inc. 29 前提知識のインストールができたところで本題

  31. 30 © 2021 Ateam Inc. 30 70万通りのURLを持つサービスを Next.jsに導入する際の一番大きな壁

  32. 31 © 2021 Ateam Inc. 31 デプロイ時間

  33. 32 © 2021 Ateam Inc. 32 70万通りのページを生成するのにどれだけ時間がかかるか?

  34. 33 © 2021 Ateam Inc. 33 1ページ生成100msと仮定しても

  35. 34 © 2021 Ateam Inc. 34 約19時間半

  36. 35 © 2021 Ateam Inc. 35 デプロイで1日が終わってしまう

  37. 36 © 2021 Ateam Inc. 36 先程の居酒屋の例で解決策を探る

  38. 37 © 2021 Ateam Inc. 37 メニューが多い居酒屋はどうしているのか?

  39. 38 © 2021 Ateam Inc. 38 人気メニューや手間のかかるメニューは 作り置き(仕込みを)して

  40. 39 © 2021 Ateam Inc. 39 それ以外のメニューは 注文を受けてから作っている

  41. 40 © 2021 Ateam Inc. 40 実際のサービスに当てはめると

  42. 41 © 2021 Ateam Inc. 41 PV上位コンテンツをデプロイ時に生成し

  43. 42 © 2021 Ateam Inc. 42 それ以外はリクエストのタイミングで生成して 以降のリクエストはキャッシュを返却する

  44. 43 © 2021 Ateam Inc. 43 ということができればデプロイ時間を短縮できるし パフォーマンスも問題なさそう

  45. 44 © 2021 Ateam Inc. 44 ではNext.jsにおいてビルドするターゲットは何で決まるのか

  46. 45 © 2021 Ateam Inc. 45 getStaticPaths: SG/ISRのデプロイ時のビルドターゲット(パス)を決定する関数 返り値に fallback:

    true(or "blocking") を指定すると、 ビルドターゲットにないパスでリクエストを受けた際にビルドを行う。(遅延ビルド)
  47. 46 © 2021 Ateam Inc. 46 getStaticPathsの設定で 3種類のデプロイパータンを作ることができる

  48. 47 © 2021 Ateam Inc. 47 フルデプロイビルドパターン 全ページをデプロイ時にビルド • 全ページ一定のアクセス量があるページ群に有効

    • BFFと通信してコンテンツを生成する場合、最大でも4桁程度のページ数が現実的 フルデプロイビルドパターン [slag].tsx PV 多 PV 少
  49. 48 © 2021 Ateam Inc. 48 フルリクエストビルドパターン デプロイ時のビルドを全スキップし、リクエスト時にビルド • デプロイは高速

    <> 初アクセスはコンテンツを生成する分、多少TTFBが遅くなる • URLパターンがかけ合わせ等で指数関数的に増加するページ群に有効 フルリクエストビルドパターン product/[id]/sub.tsx PV 多 PV 少
  50. 49 © 2021 Ateam Inc. 49 ハイブリッドビルドパターン 一部のページをデプロイ時、それ以外をリクエスト時にビルド • アクセス数に偏りがあるページ群で強い効果を発揮

    (例: 主要都市と地方) • デプロイ時間と相談しながらビルド対象数を選択する デプロイビルド リクエストビルド search/[prefecture]/[city]/[condition].tsx PV 多 PV 少
  51. 50 © 2021 Ateam Inc. 50 この3種類を適切に設定し

  52. 51 © 2021 Ateam Inc. 51 ライフドットでは全PVにおける6~7割が 初回アクセスでもビルド済みURLに到達できるようにした (※PVの分散は均一ではないことに注意)

  53. 52 © 2021 Ateam Inc. 52 記事 霊園リスト&検索 霊園詳細 フルデプロイビルド

    ハイブリッドビルド(単一条件) + フルリクエストビルド(掛合わせ条件) ハイブリッドビルド(メインページ) + フルリクエストビルド(サブページ)
  54. 53 © 2021 Ateam Inc. 53 デプロイに要する時間はこうなった

  55. 54 © 2021 Ateam Inc. 54 記事 霊園リスト&検索 霊園詳細 フルデプロイビルド

    ハイブリッドビルド(単一条件) + フルリクエストビルド(掛合わせ条件) ハイブリッドビルド(メインページ) + フルリクエストビルド(サブページ) 45分
  56. 55 © 2021 Ateam Inc. 55 しかし

  57. 56 © 2021 Ateam Inc. 56 Vercel(チームプラン)の パイプラインのタイムアウトは45分

  58. 57 © 2021 Ateam Inc. 57 45分の間にビルドだけでなく エッジへの配備まで完了させなければならない

  59. 58 © 2021 Ateam Inc. 58 ビルド時間の長さに比例してエラーの発生確率も上がる デプロイ終盤のエラー発生は辛いので 15分くらいでデプロイが完了できればなあ。。。

  60. 59 © 2021 Ateam Inc. 59 ならば さらにデプロイ時間を短縮!

  61. 60 © 2021 Ateam Inc. 60 さっきの居酒屋の例に話を戻そう

  62. 61 © 2021 Ateam Inc. 61

  63. 62 © 2021 Ateam Inc. 62

  64. 63 © 2021 Ateam Inc. 63 目的別でサービスを縦割りし それぞれのデプロイを独立して行うことで時間短縮

  65. 64 © 2021 Ateam Inc. 64 www.lifedot.jp Vercel ・・・ ・・・

  66. 65 © 2021 Ateam Inc. 65 product.vercel.lifedot.jp search.vercel.lifedot.jp article.vercel.lifedot.jp 目的別でサービスを縦割り

  67. 66 © 2021 Ateam Inc. 66 www.lifedot.jp /db/*/ /pref-*/city-*/*/ /pref-*/st-*/*/

    /pref-*/cond-*/*/ /ohaka/[a-z]+/ product.vercel.lifedot.jp article.vercel.lifedot.jp search.vercel.lifedot.jp CDN (CloudFront) + エッジコンピューティング (LambdaEdge) で統合
  68. 67 © 2021 Ateam Inc. 67 この構成でTTFBは50ms~100ms強 ※通信環境によって多少異なる ※それぞれ計測しているページは別(無作為に選別)

  69. 68 © 2021 Ateam Inc. 68 十分な速度が出ている (Googleは200msを下回ること推奨している)

  70. 69 © 2021 Ateam Inc. 69 そして肝心なビルド時間は

  71. 70 © 2021 Ateam Inc. 70 記事 霊園リスト&検索 霊園詳細 15分

    15分 15分 それぞれ並行してビルドされるので 15分に短縮
  72. 71 © 2021 Ateam Inc. 71 🎉

  73. 72 © 2021 Ateam Inc. 72 そもそもどうやってサービスのコードを分割するのか?

  74. 73 © 2021 Ateam Inc. 73 一部分の変更で 全体のデプロイが実行されるのは効率が悪い

  75. 74 © 2021 Ateam Inc. 74 リポジトリを分ける? 共有レイアウト・コンポネントはどうする?

  76. 75 © 2021 Ateam Inc. 75 開発も効率化したい!

  77. 76 © 2021 Ateam Inc. 76 Nxでのモノレポ戦略を採用

  78. 77 © 2021 Ateam Inc. 77 NxとはJSベースのモノレポ用開発ツール

  79. 78 © 2021 Ateam Inc. 78 特徴

  80. 79 © 2021 Ateam Inc. 79 Storybook, Cypress, Jest, ESLint

    などが標準配備される テストを書く文化を浸透させやすい https://nx.dev
  81. 80 © 2021 Ateam Inc. 80 package.json と node_modules がリポジトリに1つなので

    依存パッケージのアップデートなどバージョン管理が楽 ※よく比較にあがる lerna などはルートと各appごとに発生する (ただし志向や用途が違うので単純比較していいものではない)
  82. 81 © 2021 Ateam Inc. 81 vs code や IntelliJ用の公式プラグインがあり

    クリックでビルド&サーブしたりテスト実行できる 複雑なコマンド学習をメンバーに強要しなくて良い
  83. 82 © 2021 Ateam Inc. 82 appsとlibsが基本構造 共通モジュールはlibsに配備 自動的にプロジェクト名でエイリアスされる 無意識的にnpmモジュールライクな参照が可能

    import { Header } "@lifedot/components" import { useStockList } "@lifedot/hooks" libs apps article search product components relay(graphql) hooks, router, layouts, ...etc. @lifedot/components
  84. 83 © 2021 Ateam Inc. 83 apps article search product

    product.vercel.lifedot.jp search.vercel.lifedot.jp article.vercel.lifedot.jp Vercel の "Ignored Build Step" と組み合わせることで 変更が生じたappsのみデプロイできる ❌ ❌ update
  85. 84 © 2021 Ateam Inc. 84 各PJが独立して15分でデプロイが可能 & プロジェクトを絞ってデプロイできるようになった

  86. 85 © 2021 Ateam Inc. 85 🎉

  87. 86 © 2021 Ateam Inc. 86 今日紹介したこと

  88. 87 © 2021 Ateam Inc. 87 1. 3パターンのデプロイ方法と遅延ビルドの活用 • フルデプロイビルド

    • フルリクエストビルド • ハイブリッドビルド 2. サービスの縦割りと CDN+エッジコンピューティングによる統合 3. Nxによるリポジトリのモノレポ化
  89. 88 © 2021 Ateam Inc. 88 今日紹介しきれなかったこと

  90. 89 © 2021 Ateam Inc. 89 1. バンドルサイズの削減格闘記 2. 効率の良いキャッシュを目指した変動

    revalidate 3. GraphQLによるパフォーマンス改善の話
  91. 90 © 2021 Ateam Inc. 90 またの機会にお話させていただきます

  92. 91 © 2021 Ateam Inc. 91 ご質問やもっと詳しく聞きたい方は Twitter でどうぞ! @aiji42_dev

  93. 92 ITにできることを、次々と。