あなたのNextJSアプリケーションでRedis雲を使用する


最近、YutuberとJavaScript Enphenshipは、NextJS Webアプリケーションで高速クラウドデータストレージとしてRedis Enterprise Cloudを利用することを発表しました.私は完全なスタックアプリケーションのメインデータベースとしてメモリ内のデータベースを使用することについてのフェンスの上にいたが、Redisエンタープライズクラウドサービスの提供- 200ドルのバウチャーと一緒に-私は十分に私はニューヨーク大学に製品デモのために構築されたNextJSアプリケーションのランタイムキャッシュとしてそれをしようとして興味を持っていた.
Redis Enterprice Cloud Serviceの提供ページに到着すると、私はまだ200ドルのクレジットを使っていないかどうかわからなかったので、フリー層を選んだ.無料サービス層-あなたが無料で何かを想像するように-多くの提供していません:30 MBの最大30の同時接続で1つの専用のデータベースのRAM.

あなたが並行性のために特定の要件を持っているアプリケーションを構築していない限り、30の最大接続は問題のように見えないかもしれません.それがノード・サーバーのrecommended that only one or two Redis client would be instantiated then reusedであるので、我々がノード・サーバーとREDISキャッシュ間の接続を確立しているなら、この声明は本当でありえました.この場合、サーバが走っていて、Redisと通信するとき、必要な接続(clients are connections in Redis)の限られた数があります.
しかし、あなたがNextJSアプリケーションでRedis Enterprise Cloudを使用していて、あなたのバックエンドサービスをServerlessな機能を使用してオーケストレーションしているなら、ものは非常に異なります.nextjsとserverless関数の基礎を十分理解していなければ、このエラーに遭遇し、原因を理解することはありません.

ERR max number of clients reached


私が1つのアプリケーションでREDISに接続しているだけであるならば、どのように、30のすべての接続が占められるかは、可能ですか?答えを明らかにする前に、いくつかのコードを見てみましょう.
import { Client, Entity, Schema, Repository } from 'redis-om';

const client = new Client();

async function connect() {
    if (!client.isOpen()) {
        await client.open(process.env.REDIS_URL);
    }
}
Fireship's tutorialからコピーされたコード作品です.それは"Redis-OM"ライブラリの助けを借りてREDISクライアントをインスタンス化し、クライアントとREDISの間の接続を確立するために使用できる“接続”機能を宣言します.コードが指定するように、「接続」機能はクライアントとREDISの間にオープン接続が存在しないなら、接続を開くのを試みるだけです.
const client = createClient({ url: process.env.REDIS_URL });

export const connect = async () => {
  if (client.isOpen) {
    console.log("Already connected to Redis");
    return;
  }

  await client.connect();
  console.log("Connected successfully.");
};
"Node-Redis"ライブラリが使用されている場合は、別のコードの部分です.わずかな違いがありますが、ロジックは同じです.クライアントとREDISの間に確立された既存の接続が存在しない場合にのみ接続を開きます.
コードのどちらかの部分がここで紙の上で意味をなします:コードがアプリケーションが稼働していて、実行している時に一度だけ実行されるので、クライアントの1つのインスタンスだけがつくられます、そして、「接続」関数は一度だけ接続を作成するでしょう.
悪い.NextjsのServerlessな関数とEdge関数がリソース配分に基づいて非常にダイナミックな環境で実行されることを忘れないでください.そして、機能が実行される環境があなたのNextJsが構築されて、展開される環境(例えばVercel、Netlifyなど)と同じでないことを意味します.したがって、あなたがNextJS APIルートを作成しているとき(これらのルートは、NextJSアプリがVercel、NetLifyまたは類似したプラットホームで展開されるならば、Serverlessな機能によって実現されます)、彼らが「Connect」機能を呼んで、それからREDISでデータと対話してもらうために、/Page/APIフォルダの下で展開します.あらゆるServerlessな関数実行がREDISへの接続が以前に開かれなかった異なった環境にあるのは、ほとんど避けられません.このセットアップで、API呼び出しのため、各々のServerlessな関数呼び出しはあなたのRedis雲データベースにユニークな接続を作成しようとします.理論的には、Redisに接続しようとするServerless関数の30の呼び出しは、自由層の許容数の接続を排出できます.さらに悪いことに、redisは接続タイムアウトのデフォルト設定を持っていないので、クライアント側のコードがクリーンアップしない限り、接続が生成されます.
あなたがすでに接続の最大数を持っているRedis雲で足止めされるならば、RedisInsightを使用しているRedis雲に接続して、すべての基本的な接続を避けるためにCLIENT KILL TYPE normalコマンドを実行してください.
ServerlessなNextJSアプリケーションの設定では、コードがREDISデータと相互作用した後、常に接続を閉じる必要があります.チュートリアルを完了するには、以下の例を挙げます.
//Initialize the Redis client in global execution context to ensure uniqueness of the client
let client = global.redis;

//If no Redis client is found, create the client using Redis connection string
if (!client) {
  client = global.redis = createClient({ url: process.env.REDIS_URL });
}

//Open connection only when there is no existing connection
export const connect = async () => {
  if (client.isOpen) {
    console.log("Already connected to Redis");
    return;
  }

  await client.connect();
  console.log("Connected successfully.");
};

//Close connection only when there is an existing connection
export const disconnect = async () => {
  if (!client.isOpen) {
    return;
  }
  await client.quit();
  console.log("Disconnected.");
};

//Retrieve the cached data
export const getcache = async () => {
  const cache = await redis.get("cacheBetachSite");
  return cache;
};
コメントはかなり自明ですので、ここではあまり詳しく説明しません.これらのヘルパー関数がAPIルートやNextJS SSG/SSR関数でどのように使用されているのか疑問に思っているなら、次の2つです.
  • NEXTJS SSG/SSR機能
  • export const getStaticProps: GetStaticProps = async () => {
      try {
        await connect();
        const cachedData = await getcache();
        await disconnect();
        return {
          props: {
            cachedData
          },
        };
      } catch (error: any) {
        console.log(error.message);
        return {
          props: {
            error,
          },
        };
      }
    };
    
    Serverlessな機能によってサポートされる
  • APIルート
  • export default async function demoRoute(
      _req: NextApiRequest,
      res: NextApiResponse
    ) {
      try {
        await connect();
        const cachedData = await getcache();
        await disconnect();
        return res.status(200).json(cachedData);
      } catch (error: any) {
        return res.status(500).json({ error: "Unknown error." });
      }
    }
    
    ITコミュニティの一部として、我々は常に1つの技術やツールの様々なチュートリアルや文書を見つけることができるという祝福を持って、チュートリアルやドキュメントは、シームレスに各個人のユースケースにシームレスに適合することはできません.

    Be adventurous and diligent, always do your own recon before following others' footprints.