見出し画像

Next.jsでSSRしたページにFastlyでCacheを設定する

どうも。
今回は個人的にFastlyを試してみたので、少しご紹介したいと思います。

さて、まずはNext.jsとFastlyを組み合わせてキャッシュを導入していきましょう。
Next.jsといえば、Vercelが有名ですね。
Vercelを利用する場合は、特に意識せずにエッジネットワークによるキャッシュが提供されます。

ですが、Vercel以外のオプションとしてCloud Runを使用してホスティングする場合は、FastlyやCloudFlareなどのCDNを使ってキャッシュを構築する必要があります。

1.Fastlyについて

FastlyとはCDN、画像の最適化、ビデオとストリーミング、クラウドセキュリティ、負荷分散などを提供してくれるサービスです。

CDN とは、コンテンツデリバリーネットワークの略称で、ウェブコンテンツ(画像・動画等)を効率的に配信するためのネットワークを指します。

ざっくり言うと、サーバーへの負荷を減らして高速にしてくれるやつです。

通常データを取得する際、データを保存しているサーバーまでデータを取得しにいくわけですが、物理的な距離が遠ければ遠いほど取得に時間がかかります。
また、データの取得の量や回数が多ければ多いほどサーバーへの負荷がかかります。

そういったときにサイトを高速に、サーバーへのデータリクエストやレスポンスを軽くする!というのがFastlyです。

2.Next.jsをCloud Runにデプロイする

FastlyはCDN(コンテンツデリバリーネットワーク)であり、画像の最適化、ビデオとストリーミング、クラウドセキュリティ、負荷分散などのサービスを提供しています。
CDNはウェブコンテンツ(画像、動画など)を効率的に配信するためのネットワークです。

要するに、Fastlyはサーバーへの負荷を軽減し、配信速度を高速化する役割を果たしてくれるものです。
通常、データを取得する場合、データを保存しているサーバーにアクセスしてデータを取得しますが、物理的な距離が遠ければ取得に時間がかかります。
また、データの量や回数が多ければサーバーに負荷がかかります。
こうした場合にFastlyを利用することで、ウェブサイトを高速化し、サーバーへのデータリクエストやレスポンスを軽減することができます。

2-1.next.config.js で設定する場合

// next.config.js

const cacheHeaders = [
  {
    key: 'Cache-Control',
    value: 'max-age=300', // 300秒キャッシュされる
  },
];
module.exports = {
  {
    source: '/*',
    headers: cacheHeaders,
  }
};

2-2.getServerSidePropsで設定する場合

// pages/index.tsx

import Head from 'next/head'
import Image from 'next/image'
import styles from '../styles/Home.module.css'

export default function Home(props) {
  return (
    <div className={styles.container}>
      <Head>
        <title>Create Next App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <h1 className={styles.title}>
          Welcome to <a href="https://nextjs.org">Next.js to Cloud Run! and Fastly Now! {props.timestr}</a>
        </h1>
      </main>
    </div>
  )
}

export async function getServerSideProps(context) {
  const timestr = new Date().toISOString();
  context.res.setHeader('Cache-Control', 'public, max-age=300'); // 300秒キャッシュされる
  return {
    props: {timestr},
  }
}

getServerSideProps内で、headerに300秒のキャッシュを設定するようにします。
そして、Cloud Runへアプリケーションをデプロイします。
Next.jsをCloud Runにデプロイする方法については、以下のリンクを参照してください。

Cloud Runに正常にデプロイされると、以下のようなコンソール画面が表示されます。

Cloud Runのデプロイできたときの表示

3.Fastlyのアカウントを作成

Fastlyの無料アカウントを利用します。
ただし、独自ドメインやSSLの活用は有料アカウントのみ可能ですので、注意しましょう。
無料アカウントを作成できたら、「Create a Delivery Service」からサービスを作成します。

Fastlyでサービスを作る前の表示

1〜2を進めていきます。

Fastlyでサービスを作成後の表示

3-1.domain

ドメイン選択画面で ${name}.global.ssl.fastly.net のように入力します。独自ドメインを使用する場合は、有料アカウントが必要です。

ドメイン設定画面の表示

3-2.Host

先程のCloud Runにデプロイされた ${host_url}:443 というホストURLにポート番号をつけて設定します。

ホスト設定画面の表示

1〜2の手順を完了したら、Activateボタンを押して設定を反映させましょう。
これにより、「Cloud Run = Origin」と「Fastly = CDN」の準備が整います。

さて、キャッシュが正しく動作しているかどうかを確認してみましょう。
今回は処理の中で現在の時刻を表示するようにしていますので、それを確認してみましょう。
まずはCloud RunのOriginURLにアクセスしてみてください。ブラウザをリロードすると、毎秒時間が進んでいくことが確認できるはずです。

OriginのURLにアクセスしたときの表示

次に、Fastlyで設定した ${name}.global.ssl.fastly.net にアクセスしてみましょう。
初回アクセスなので、Originにアクセスした時間から数秒が経過した時刻が表示されるはずです。

FastlyにキャッシュされているURLにアクセスしたときの表示

1回目はキャッシュされていないため、現在の時刻が表示されますね。
それでは、ブラウザをリロードしてみましょう。
すると、先程と同じ時刻が表示され続けるはずです。

実際にキャッシュされているかどうかを確認するために、 ${name}.global.ssl.fastly.net のブラウザコンソールのNetworkタブから確認してみましょう。

NetWorkタブの表示

X-Cache: HITと表示されているので、しっかりとキャッシュされていますね。
キャッシュの設定が300秒になっているため、300秒後にブラウザをリロードすると表示されている時刻が更新されます。
その後も300秒間は同じ時刻が表示され続けるはずです。

Cloud Runにデプロイする場合は、CDNを自分で考えて用意する必要がありますが、Vercel × Next.jsを使用すると自動でCDNとして機能してくれます。ただし、Vercelも一長一短なので、どのCDNが最適かはアプリケーションの特性によって異なるため、柔軟に考えましょう。

いかがでしたか?これでSSRされている動的なコンテンツをキャッシュすることができるようになりました。

4.任意のタイミングでキャッシュを削除したい

キャッシュを導入すると、オリジンに更新があった場合でも300秒間は古い情報が表示され続けてしまいます。
しかし、更新時にはすぐに最新の情報を反映したいと思うことでしょう。
キャッシュを導入する場合、できるだけキャッシュしておきつつ、必要な時には瞬時に更新したいというニーズがあります。

そのため、CDNにはパージという機能が存在します。
これはキャッシュを削除する機能です。

5.動的にキャッシュを削除できないのか?

Vercelでは動的にキャッシュを削除する方法は提供されていません。
一方、Fastlyではインスタント・パージという機能が利用できます。

インスタント・パージはFastlyの管理画面から手動で行うことができますし、API経由でもパージすることが可能です。
ただし、デフォルトでは「認証なし」でパージAPIを利用できてしまうため、キーがない場合でもパージが実行されないように注意しましょう。
キーを設定することで、正当なリクエストのみがパージを実行できるようになります。

Fastlyは他のCDNよりも高速にパージが可能です。
この高速なパージ機能により、キャッシュを導入する場面が増えると考えられます。
特に在庫管理などリアルタイムなデータ更新が必要なECサイトなどではキャッシュの活用が難しい場合もありますが、頻繁に変更されないコンテンツに関しては積極的にキャッシュを利用していきましょう。
これにより、コンテンツの高速な配信とサーバーへの負荷軽減が実現できます。

6.インスタント・パージの懸念点

そんな便利なインスタント・パージについてコメントを見て、確かにその利点を感じました。

例えばhttps://zenn.dev/foo/barというページの内容が更新されたとします。インスタントパージはデータの更新と合わせてバックエンドから行うのが自然だと思います。
しかしパージの対象はフロントエンドのURLです。つまり、バックエンドがフロントエンドについてよく知っている必要が出てきます(このデータが更新されたときにキャッシュをパージしなければならないURLはどれか)。

Next.jsのISRで動的コンテンツをキャッシュするときの戦略

この場合、インスタント・パージの選択は微妙だと感じます。

ECサイトの在庫を参照するページやカート画面のように、強い整合性が求められる場面ではキャッシュの利用は難しいでしょう。
しかし、それ以外のケースではキャッシュは非常に有効に機能します。

また、最近の話題として、FastlyよりCompute@EdgeでNext.jsが動作可能になりました。

Fastly の新しい next-compute-js ライブラリを使用することで、Compute@Edge プラットフォーム上で Next.js アプリケーションをホストできるようになりました。これにより、Next.js 開発者のエクスペリエンスが向上し、圧倒的なスピードを誇る Fastly のグローバルエッジネットワークのメリットが得られます。オリジンサーバーも必要ありません。

Fastly で Next.js アプリケーションを実行

なんと、オリジンサーバーも必要ないということです。
まさにエッジ周りが非常に注目されていますね。
これからもエッジ技術の最新情報に追いつきながら進んでいきたいと思います。

それでは。

この記事が気に入ったらサポートをしてみませんか?