Redis
 Computer >> コンピューター >  >> プログラミング >> Redis

RedisでNext.jsアプリケーションを高速化する方法

Next.jsは、サーバーサイドレンダリング(SSR)と静的サイト生成(SSG)を組み合わせた、非常に人気の高いWebフレームワークです。SSGはCDNキャッシュによってWebサイトの表示速度を向上させ、SSRはSEO対策や動的なデータ処理において大きな強みとなります。

サーバーサイドレンダリングは、フルスタックアプリケーション開発を支援してくれる優れた機能です。しかし、注意深く設計しないと、Next.jsサイトのパフォーマンスは容易に低下してしまいます。本記事では、Redisを活用してNext.jsのAPI呼び出しを高速化する方法を解説します。その前に、まずはよりシンプルなパフォーマンス改善手法についても簡単にご紹介します。

API呼び出しにはSWRを活用する

SWRは非常に賢いデータフェッチライブラリです。HTTP RFC 5861で定義されているキャッシュ戦略「stale-while-revalidate」を採用しています。SWRでAPIを呼び出すと、まずキャッシュされたデータを即座に返し、その後バックグラウンドで非同期に最新データを取得してUIを更新します。さらに、データの鮮度に対する許容度に応じてrefreshIntervalを設定することも可能です。

const { data: user } = useSWR('/api/user', { refreshInterval: 2000 })

上記のコードでは、ユーザーAPIが2秒ごとに自動的に更新されます。

Redisによるキャッシング

SWRはシンプルかつ効果的ですが、サーバーサイドでのキャッシングが必要になるケースもあります。

  • クライアント数が多い場合: クライアントサイドキャッシュはクライアント側のパフォーマンスを向上させますが、クライアント数が膨大になるとサーバー側のリソースに高負荷がかかり、結果としてクライアント側のパフォーマンスにも悪影響を及ぼします。
  • 外部APIに利用制限がある場合: クォータ付きの外部APIを利用している場合は、サーバー側でAPI使用量を管理したいはずです。管理しないと、多数のクライアントによってあっという間にAPIの上限に達してしまいます。
  • 動的な入力値を扱う場合: サーバー側で動的な入力をもとに計算・取得・加工されるリソースについては、クライアントサイドキャッシュはあまり効果を発揮しません。

実例プロジェクト:Covidトラッカー

ここでは、Javier Aviles氏のCovid APIを使用し、感染者数の多い上位10カ国を表示するプロジェクトを取り上げます。デモサイトソースコードも公開されているので、ぜひ確認してみてください。

このプロジェクトでは、Covid APIからのレスポンスをRedisでキャッシュします。これにより以下のメリットが得られます。

  • レスポンスの大幅な高速化: 実際のサイトで確認すると、Covid APIへの直接アクセスには数百ミリ秒かかるのに対し、Redisからの取得はわずか1〜2ミリ秒で完了します。
  • 外部APIの保護: 大量のリクエストによってCovid APIへ過度な負荷をかけることを防ぎます。

APIコード

以下のコードは、まずAPIの結果がRedisにキャッシュ済みかどうかを確認します。キャッシュが存在しない場合は、Covid APIから全世界の国リストを取得し、当日の感染者数順にソートして上位10カ国をRedisに保存します。保存時にはEX 60パラメータを指定しており、これにより60秒後にエントリが自動的に削除されます。

import Redis from "ioredis";

let redis = new Redis(process.env.REDIS_URL);

export default async (req, res) => {
  let start = Date.now();
  let cache = await redis.get("cache");
  cache = JSON.parse(cache);
  let result = {};
  if (cache) {
    console.log("loading from cache");
    result.data = cache;
    result.type = "redis";
    result.latency = Date.now() - start;
    return res.status(200).json(result);
  } else {
    console.log("loading from api");
    start = Date.now();
    return fetch("https://coronavirus-19-api.herokuapp.com/countries")
      .then((r) => r.json())
      .then((data) => {
        data.sort(function (a, b) {
          return b.todayCases - a.todayCases;
        });
        result.data = data.splice(1, 11);
        result.type = "api";
        result.latency = Date.now() - start;
        redis.set("cache", JSON.stringify(result.data), "EX", 60);
        return res.status(200).json(result);
      });
  }
};

UIコード

UI部分はシンプルなReactコードです。SWRを使ってAPIからデータを取得します。

export default function Home() {
  function refresh(e) {
    e.preventDefault();
    window.location.reload();
  }
  const { data, error } = useSWR("api/data", fetcher);
  if (error) return "An error has occurred.";
  if (!data) return "Loading...";
  return (
    <div className={styles.container}>
      <Head>
        <title>Covid Tracker</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}>Covid Tracker</h1>

        <p className={styles.description}>
          Top 10 countries with the most cases today
        </p>

        <div className={styles.grid}>
          <div className={styles.card} onClick={refresh}>
            <table className={styles.table}>
              <thead>
                <tr>
                  <th>Country</th>
                  <th>Today Cases</th>
                  <th>Today Deaths</th>
                </tr>
              </thead>
              <tbody>
                {data.data.map((item) => (
                  <tr>
                    <td>{item.country}</td>
                    <td>{item.todayCases}</td>
                    <td>{item.todayDeaths}</td>
                  </tr>
                ))}
              </tbody>
            </table>
            <br />
            <em>
              Loaded from {data.type} in <b>{data.latency}</b> milliseconds.
              Click to reload.
            </em>
          </div>
        </div>
      </main>

      <footer className={styles.footer}>
        This is a sample project for the blogpost &nbsp;
        <a
          href="https://blog.upstash.com/nextjs-caching-with-redis"
          target="_blank"
          rel="noopener noreferrer"
        >
          Speed up your Next.js application using Serverless Redis for caching.
        </a>
      </footer>
    </div>
  );
}

外部リンク

  1. Cloudflare WorkersとRedisで実現するエッジコンピューティング活用術

    エッジコンピューティングは、近年もっとも注目されている技術のひとつです。CDNがファイルをユーザーの近くに配置できるようにしたのと同じように、エッジコンピューティングはアプリケーションそのものをユーザーの近くで実行できるようにします。これにより、開発者はグローバルに分散され、高いパフォーマンスを発揮するアプリケーションを構築できるようになります。 Cloudflare Workersとステートレス性の課題 現在この分野をリードしている製品がCloudflare Workersです。コールドスタートのないサーバーレス実行環境を提供し、Cloudflareのグローバルネットワークを活かすことで、ア

  2. MSCONFIGでPCを高速化する方法|Windowsの起動を最適化する手順を解説

    Windows向けに作られたコマンドの中で、最も優れていると私たちが考えるのがMSCONFIGです。MSCONFIGは過去のWindowsバージョンから搭載されており、Windows 10にも当然のように存在しています。この記事を読み進めれば、その理由がきっと分かるはずです。MSCONFIGを使ってPCを高速化する方法を、ぜひマスターしましょう。 MSCONFIGはなぜ便利なのか? MSCONFIGではさまざまな設定を管理できますが、特に注目したいのは、自動的に起動するプログラム(スタートアップ)を制御できる点です。これらのプログラムは貴重なメモリを消費しており、PCの読み込み時間を長引かせ、