Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

AijiUejima
October 28, 2021

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

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

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

AijiUejima

October 28, 2021
Tweet

More Decks by AijiUejima

Other Decks in Technology

Transcript

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

    View full-size slide

  2. 1
    © 2021 Ateam Inc. 1
    Uejima Aiji
    リードエンジニア@株式会社エイチームライフスタイル
    Twitter: aiji42_dev
    8年のキャリアの中で、フロントエンジニアよりも
    バックエンドエンジニアとしてのキャリアのほうが長い (3:7くらい)
    でも最近はフロントエンドがメイン

    View full-size slide

  3. 2
    © 2021 Ateam Inc. 2
    今日はURLが膨大なサービスに
    Next.jsを導入した際の

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  8. 7
    © 2021 Ateam Inc. 7
    トップ 記事 霊園リスト&検索 霊園詳細
    1K Pages 700K Pages 30K Pages
    エントリー
    エリア(市区町村・駅)x霊園特徴(樹木葬, 納骨堂...etc.)

    View full-size slide

  9. 8
    © 2021 Ateam Inc. 8
    もともとはパフォーマンスが非常に悪かった

    View full-size slide

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

    View full-size slide

  11. 10
    © 2021 Ateam Inc. 10
    LCP (Largest Contentful Paint)
    CLS (Cumulative Layout Shift)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  16. 15
    © 2021 Ateam Inc. 15
    LCP CLS

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  23. 22
    © 2021 Ateam Inc. 22
    SG (Static Generate)
    (少し前まで SSG と呼ばれていた)

    View full-size slide

  24. 23
    © 2021 Ateam Inc. 23
    開店前にドリンクを作り置きしておく

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  46. 45
    © 2021 Ateam Inc. 45
    getStaticPaths: SG/ISRのデプロイ時のビルドターゲット(パス)を決定する関数
    返り値に fallback: true(or "blocking") を指定すると、
    ビルドターゲットにないパスでリクエストを受けた際にビルドを行う。(遅延ビルド)

    View full-size slide

  47. 46
    © 2021 Ateam Inc. 46
    getStaticPathsの設定で
    3種類のデプロイパータンを作ることができる

    View full-size slide

  48. 47
    © 2021 Ateam Inc. 47
    フルデプロイビルドパターン 全ページをデプロイ時にビルド
    • 全ページ一定のアクセス量があるページ群に有効
    • BFFと通信してコンテンツを生成する場合、最大でも4桁程度のページ数が現実的
    フルデプロイビルドパターン
    [slag].tsx
    PV

    PV

    View full-size slide

  49. 48
    © 2021 Ateam Inc. 48
    フルリクエストビルドパターン デプロイ時のビルドを全スキップし、リクエスト時にビルド
    • デプロイは高速 <> 初アクセスはコンテンツを生成する分、多少TTFBが遅くなる
    • URLパターンがかけ合わせ等で指数関数的に増加するページ群に有効
    フルリクエストビルドパターン
    product/[id]/sub.tsx
    PV

    PV

    View full-size slide

  50. 49
    © 2021 Ateam Inc. 49
    ハイブリッドビルドパターン 一部のページをデプロイ時、それ以外をリクエスト時にビルド
    • アクセス数に偏りがあるページ群で強い効果を発揮 (例: 主要都市と地方)
    • デプロイ時間と相談しながらビルド対象数を選択する
    デプロイビルド リクエストビルド
    search/[prefecture]/[city]/[condition].tsx
    PV

    PV

    View full-size slide

  51. 50
    © 2021 Ateam Inc. 50
    この3種類を適切に設定し

    View full-size slide

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

    View full-size slide

  53. 52
    © 2021 Ateam Inc. 52
    記事 霊園リスト&検索 霊園詳細
    フルデプロイビルド ハイブリッドビルド(単一条件)
    +
    フルリクエストビルド(掛合わせ条件)
    ハイブリッドビルド(メインページ)
    +
    フルリクエストビルド(サブページ)

    View full-size slide

  54. 53
    © 2021 Ateam Inc. 53
    デプロイに要する時間はこうなった

    View full-size slide

  55. 54
    © 2021 Ateam Inc. 54
    記事 霊園リスト&検索 霊園詳細
    フルデプロイビルド ハイブリッドビルド(単一条件)
    +
    フルリクエストビルド(掛合わせ条件)
    ハイブリッドビルド(メインページ)
    +
    フルリクエストビルド(サブページ)
    45分

    View full-size slide

  56. 55
    © 2021 Ateam Inc. 55
    しかし

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  62. 61
    © 2021 Ateam Inc. 61

    View full-size slide

  63. 62
    © 2021 Ateam Inc. 62

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  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)
    で統合

    View full-size slide

  68. 67
    © 2021 Ateam Inc. 67
    この構成でTTFBは50ms~100ms強
    ※通信環境によって多少異なる
    ※それぞれ計測しているページは別(無作為に選別)

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  71. 70
    © 2021 Ateam Inc. 70
    記事 霊園リスト&検索 霊園詳細
    15分 15分 15分
    それぞれ並行してビルドされるので
    15分に短縮

    View full-size slide

  72. 71
    © 2021 Ateam Inc. 71
    🎉

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  79. 78
    © 2021 Ateam Inc. 78
    特徴

    View full-size slide

  80. 79
    © 2021 Ateam Inc. 79
    Storybook, Cypress, Jest, ESLint
    などが標準配備される
    テストを書く文化を浸透させやすい
    https://nx.dev

    View full-size slide

  81. 80
    © 2021 Ateam Inc. 80
    package.json と node_modules がリポジトリに1つなので
    依存パッケージのアップデートなどバージョン管理が楽
    ※よく比較にあがる lerna などはルートと各appごとに発生する
    (ただし志向や用途が違うので単純比較していいものではない)

    View full-size slide

  82. 81
    © 2021 Ateam Inc. 81
    vs code や IntelliJ用の公式プラグインがあり
    クリックでビルド&サーブしたりテスト実行できる
    複雑なコマンド学習をメンバーに強要しなくて良い

    View full-size slide

  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

    View full-size slide

  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

    View full-size slide

  85. 84
    © 2021 Ateam Inc. 84
    各PJが独立して15分でデプロイが可能
    &
    プロジェクトを絞ってデプロイできるようになった

    View full-size slide

  86. 85
    © 2021 Ateam Inc. 85
    🎉

    View full-size slide

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

    View full-size slide

  88. 87
    © 2021 Ateam Inc. 87
    1. 3パターンのデプロイ方法と遅延ビルドの活用
    • フルデプロイビルド
    • フルリクエストビルド
    • ハイブリッドビルド
    2. サービスの縦割りと
    CDN+エッジコンピューティングによる統合
    3. Nxによるリポジトリのモノレポ化

    View full-size slide

  89. 88
    © 2021 Ateam Inc. 88
    今日紹介しきれなかったこと

    View full-size slide

  90. 89
    © 2021 Ateam Inc. 89
    1. バンドルサイズの削減格闘記
    2. 効率の良いキャッシュを目指した変動 revalidate
    3. GraphQLによるパフォーマンス改善の話

    View full-size slide

  91. 90
    © 2021 Ateam Inc. 90
    またの機会にお話させていただきます

    View full-size slide

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

    View full-size slide

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

    View full-size slide