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

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

Next.jsと聞くと、静的なウェブサイトやReact駆動のフロントエンドを思い浮かべる方が多いかもしれません。しかし、それはNext.jsの能力の一部にすぎません。実はNext.jsは、他のバックエンドサービスと同じようにホスティングやスケーリングが可能な、本格的なバックエンドAPIの構築にも活用できます。

以前の記事では、Next.jsでAPIを構築し、Sevallaにデプロイする手順を解説しました。そのサンプルではPostgreSQLデータベースにデータを保存し、リクエストを直接処理していました。小規模なうちは問題なく動作しますが、トラフィックが増加すると、リクエストごとにデータベースへアクセスするAPIは次第に遅くなってしまいます。

そこで登場するのがキャッシュです。Redisをキャッシュレイヤーとして追加することで、Next.js APIを格段に高速かつ効率的にできます。本記事では、APIにRedisキャッシュを組み込み、Sevallaにデプロイし、実際に測定できるパフォーマンス向上までを解説します。

前回の記事でAPIの詳細を説明しているため、この記事ではこちらのリポジトリをベースとして使用します。

目次

  • キャッシュが重要な理由

  • Redisとは何か

  • プロジェクトのセットアップ

  • Redisのプロビジョニング

  • 読み取り時のキャッシュ更新

  • 書き込み時のキャッシュ更新

  • Sevallaへのデプロイ

  • RedisがNext.js APIと相性抜群である理由

  • まとめ

キャッシュが重要な理由

APIがデータベースにアクセスするたびに、時間とリソースを消費します。データベースは構造化データの保存やクエリ処理には優れていますが、毎秒数千件の読み取りリクエストに応答するような大規模な高速処理には最適化されていません。

キャッシュは、頻繁にアクセスされるデータをメモリ上に保持することでこの課題を解決します。毎回データベースに問い合わせる代わりに、キャッシュにデータがあればAPIはそこから直接返却できます。Redisはパフォーマンス重視で設計されたインメモリ型キーバリューストアであり、この用途に理想的です。

例えば、リクエストごとにユーザー一覧をデータベースから取得する場合、クエリの実行と結果の返却に約200msかかることがあります。Redisキャッシュを使えば、最初のリクエストで結果をメモリに保存し、以降のリクエストは10ms未満で同じデータを返せます。桁違いの改善です。

Redisとは何か

Redisは、超高速なデータベースのように動作するインメモリ型データストアです。ディスクへの読み書きではなくメモリ上でデータを保持するため、驚異的な速度を実現しています。速度が長期保存よりも重要となるキャッシュ用途でよく使われるのはこのためです。

Redisは非常に低いレイテンシで高スループットのワークロードを処理するよう設計されており、マイクロ秒単位で応答できます。そのため、APIレスポンスのキャッシュ、セッションデータの保存、チャットシステムやランキング(リーダーボード)などのリアルタイムアプリケーションの基盤といったユースケースに最適です。

従来のデータベースとは異なり、Redisはシンプルさと速度に特化しています。データをキーバリュー形式で保存するため、複雑なクエリを書かずに素早く値の取得や更新が可能です。さらに、リスト・セット・ハッシュといった高度なデータ型もサポートしており、単純なキーバリューストアよりもはるかに柔軟です。

Next.jsで構築したようなAPIと組み合わせれば、Redisはメインデータベースへの負荷を軽減しながら、クライアントへ爆速のレスポンスを届けるのに役立ちます。

プロジェクトのセットアップ

まずリポジトリをクローンしましょう。

git clone git@github.com:manishmshiva/nextjs-api-pgsql.git next-api

ディレクトリに移動し、npm installで必要なパッケージをインストールします。

cd next-api
npm i

.envファイルを作成し、Sevallaから取得したデータベースURLを環境変数として追加します。

cat .env

.envファイルは以下のようになります。

PGSQL_URL=postgres://<username>:<password>-@asia-east1-001.proxy.kinsta.app:30503/<db_name>

次に、アプリケーションを起動していくつかAPIリクエストを送り、期待どおりに動作することを確認しましょう。

アプリの起動:

npm run dev

データベースに接続できているか確認します。ブラウザでlocalhost:3000にアクセスすると、以下のJSONが返されるはずです。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

新しいユーザーを作成してみましょう。Postmanを使ってデータベースに新規エントリを登録するには、以下のJSONを含むPOSTリクエストを送信します。

{"id":"d9553bb7-2c72-4d92-876b-9c3b40a8c62c","name":"Larry","email":"larry@example.com","age":"25"}

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

ブラウザでlocalhost:3000/usersにアクセスし、レコードが作成されたことを確認します。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

これで準備完了です。次に、これらのAPIをRedisでキャッシュしていきます。

Redisのプロビジョニング

Sevallaのダッシュボードに移動し、「Databases」をクリックします。一覧から「Redis」を選択し、その他のオプションはデフォルトのままにします。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

データベースが作成されたら、「external connection」オプションをオンにして、公開アクセス可能なURLをコピーします。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

.envファイルには以下のように記述します。

REDIS_URL=redis://default:<password>@<host>:<port>

続いて、Node.js用のRedisクライアントをインストールします。

npm install ioredis

これでRedisに接続し、ユーザーAPIのキャッシュレイヤーとして利用できるようになりました。キャッシュの実装方法を見ていきましょう。

読み取り時のキャッシュ更新

以下は、Redisを使用するように更新したusers/route.tsです。

import { NextResponse } from "next/server";
import { Client } from "pg";
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL!);
async function readUsers() {
 const client = new Client({
 connectionString: process.env.PGSQL_URL,
 });
 await client.connect();
 try {
 const result = await client.query("SELECT id, name, email, age FROM users");
 return result.rows;
 } finally {
 await client.end();
 }
}
export async function GET() {
 try {
 // まずキャッシュを確認
 const cached = await redis.get("users");
 if (cached) {
 return NextResponse.json(JSON.parse(cached));
 }
 // キャッシュになければデータベースへフォールバック
 const users = await readUsers();
 // 結果をTTL 60秒でキャッシュに保存
 await redis.set("users", JSON.stringify(users), "EX", 60);
 return NextResponse.json(users);
 } catch (err) {
 return NextResponse.json({ error: "Failed to fetch users" }, { status: 500 });
 }
}

この状態で/usersにアクセスすると、次のような流れになります。

  1. APIはまずRedisを確認します。

  2. データが存在すれば、即座に返却します。

  3. 存在しなければ、PostgreSQLにクエリを実行し、結果をRedisに保存してから返却します。

これにより、繰り返しのリクエストが極めて高速になります。キャッシュの有効期限(EX 60)は、求めるデータの鮮度に応じて調整してください。

Redisキャッシュなしで/usersを10回取得すると、10回のデータベースクエリが発生します。それぞれ約150〜200msかかる可能性があり、データベースのサイズやネットワークレイテンシによって変動します。

Redisを使えば、最初のリクエストはキャッシュ生成のため約200msかかりますが、それ以降のリクエストはほぼ瞬時に、多くの場合10ms未満で完了します。これは20倍の改善です。

この高速化は、APIが毎秒数百〜数千件のリクエストにさらされる場合に大きな意味を持ちます。キャッシュはレイテンシを削減するだけでなく、データベースへの負荷も軽減してくれます。

書き込み時のキャッシュ更新

現時点ではGETリクエストのみがキャッシュを利用しています。しかし、新しいユーザーを追加した場合はどうでしょうか?キャッシュは古いデータを返し続けてしまいます。

解決策は、書き込みが発生するたびにキャッシュを更新またはクリアすることです。POSTハンドラーを以下のように更新しましょう。

export async function POST(req: Request) {
 try {
 const body = await req.json();
 const client = new Client({
 connectionString: process.env.PGSQL_URL,
 });
 await client.connect();
 const query = `
 INSERT INTO users (id, name, email, age)
 VALUES ($1, $2, $3, $4)
 RETURNING *;
 `;
 const result = await client.query(query, [
 body.id,
 body.name,
 body.email,
 body.age,
 ]);
 await client.end();
 // 次のGETで最新データを取得できるようキャッシュを無効化
 await redis.del("users");
 return NextResponse.json(result.rows[0]);
 } catch (err) {
 return NextResponse.json({ error: "Failed to add user" }, { status: 500 });
 }
}

これで、新しいユーザーが作成されるたびにusersのキャッシュがクリアされます。次のGETリクエストはデータベースから最新データを取得してキャッシュを更新し、以降は引き続きキャッシュされたデータを配信します。

Sevallaへのデプロイ

コードをGitHubにプッシュするか、筆者のリポジトリをフォークしてください。次にSevallaに移動して新しいアプリを作成します。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

ドロップダウンからリポジトリを選択し、「Automatic deployment on commit」にチェックを入れます。これにより、コードをプッシュするたびに自動的にデプロイされます。リソースセクションでは「Hobby」を選択します。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

「Create」をクリックします。「Create and deploy」ではない点に注意してください。まだPostgreSQLのURLとRedisのURLを環境変数として追加していないため、このままデプロイするとアプリがクラッシュしてしまいます。

「Environment variables」セクションに移動し、キー「PGSQL_URL」とその値としてURLを追加します。同様に「REDIS_URL」キーにもRedisのURLを追加します。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

次に「Overview」セクションに戻り、「Deploy now」をクリックします。

SevallaでRedisキャッシュを導入してNext.js APIのパフォーマンスを大幅に向上させる方法

デプロイが完了したら、「Visit app」をクリックしてAPIのライブURLを取得します。Postmanでlocalhost:3000をこの新しいURLに置き換えれば、APIをテストできます。

RedisがNext.js APIと相性抜群である理由

Redisは軽量で爆速であり、APIレスポンスのキャッシュに最適です。Next.jsの文脈では、以下の理由から自然に組み込めます。

  • APIルートはサーバーサイドで実行されるため、Redisに直接クエリできます。

  • データベース呼び出しの周りに、シンプルにキャッシュロジックを追加できます。

  • Redisはキャッシュ以外にも活用できます。レート制限、セッションストレージ、Pub/Subなども一般的なユースケースです。

Next.js、PostgreSQL、RedisをSevalla上で組み合わせれば、高速でスケーラブル、しかも簡単にデプロイできるスタックが手に入ります。

まとめ

キャッシングは単なる最適化ではなく、実運用のAPIにとって必須の仕組みです。Next.jsなら堅牢なバックエンドAPIを簡単に構築・デプロイできます。そこにRedisを加えれば、スケールしても余裕を持って対応できるAPIになります。

SevallaはマネージドなPostgreSQL、Redis、アプリホスティングをひとつの場所で提供し、すべてをつなげてくれます。いくつかの環境変数とGitHubリポジトリさえあれば、ローカル開発から本番対応済みのキャッシュ付きAPIまで、わずか数分で到達できます。

この記事をお楽しみいただけたなら、無料のAIニュースレターTuringTalks.aiにもぜひご登録ください。AIに関するハンズオンチュートリアルを多数配信しています。また、LinkedInでも活動しています。


  1. Next.js・Replicate・Redisで作るAI画像キャプションアプリ開発ガイド

    AIがますます身近な存在となる中、Replicateのような企業は機械学習モデルをプロジェクトへシームレスに組み込むことを容易にしています。 本記事では、ユーザーが画像をアップロードするとAIが生成したテキストキャプションを受け取れるWebアプリケーション「CaptionAI」の開発方法について解説します。このプロジェクトはVercelの公式テンプレートをベースに構築しており、開発の様子を収めた解説動画も公開されています。 使用する技術スタック Next.js 13(フロントエンドおよびバックエンド) Upstash Redis(レート制限) Replicate(機械学習API) Tail

  2. Redis PUBLISHコマンドの使い方 – Pub/Subでメッセージを公開する方法を解説

    このチュートリアルでは、redis-cliを使ってRedisのメッセージブローカーシステムにメッセージを公開(パブリッシュ)する方法について解説します。 PUBLISHコマンドとは PUBLISHコマンドは、Redisのメッセージブローカーにおいて、指定したチャンネルへメッセージを配信するために使用されます。コマンドを実行すると、そのメッセージを受信したサブスクライバー(購読者)の数が戻り値として返されます。 Pub/Subモデルでは、パブリッシャーとサブスクライバーが直接やり取りするのではなく、チャンネルを介して疎結合な通信を行うため、リアルタイム通知やチャットアプリケーション、イベント駆動