Redisとマングースを用いたキャッシュ層の構築


イントロダクション.


あなたがAPIを構築した場合は、キャッシュを必要とするいくつかの取得要求をキャッシュする必要があります見つける必要があります.本稿ではこの問題の解決策を紹介する.

解決法


我々はここで非常に簡単な戦略に従いますが、始める前に、マングースとノードに精通している必要があります.js

戦略


我々はすべてのブログを取得するクエリを使用して動作しているモデルを想像してください

ブログモデル


const blogSchema = new mongoose.Schema({
    owner : {
        // user in the database 
        type: mongoose.Types.ObjectId,
        required: true,
        ref: "User"
    },
    title: {
        type : String,
        required: true
    },
    tags: {
        type : [mongoose.Types.ObjectId],
    },
    blog: {
        type : String
    }
});
今すぐすべてのブログを取得するリクエスト
app.use("/api/blogs",(req,res,next)=>{
         const blogs = await Blogs.find({}); 
          res.send(blogs);
});
我々が我々が働いているもののイメージを得たあと、現在戦略に戻ってください
  • は、特定のもの
  • を求めるためにクエリをデータベースに送ります
  • AKAがキャッシュ(REDIS)に存在する前にこのクエリが取り出された場合は?
  • そうすると、キャッシュされた結果を返します
  • がなければ、REDISでそれをキャッシュして、結果
  • を返します
    ここでのトリックは、すべての操作の後に自動的に実行されるマングースの機能があるということです
    この関数はexecと呼ばれます.
    したがって、キャッシュ・ロジックを行うためにこのexec関数を上書きする必要があります.

    上書きへの第一歩
    const exec = mongoose.Query.prototype.exec;
    mongoose.Query.prototype.exec = async function (){
        // our caching logic
        return await exec.apply(this, arguments);
    }
    
    今私たちは何がキャッシュされ、何がないかを教えて何かをする必要があります.

    伝達関数の作成
    mongoose.Query.prototype.cache = function(time = 60 * 60){
        this.cacheMe = true; 
        // we will talk about cacheTime later;
        this.cacheTime = time;
        return this;
    }
    
    今私が書いたなら
    Blogs.find({}).cache(); // this is a valid code
    
    今あなたがRedis goに精通していない場合はそれに精通してください.何千ものビデオとチュートリアルがあります、そして、それはその多くの時間をとりません.
    キャッシュされた結果のデータ構造や型が必要です.いくつかの思考の後、私はこれが最良の構造であることを発見した理由と理由を説明します.
    .
    ブログのコレクション名です
    あなたがBlogs.find({"title" : "cache" , user : "some id that points to user" })をしていると言いましょう
    それから、クエリーは「タイトル」です:「キャッシュ」、「ユーザー」:「若干のid ...」OP :"クエリのメソッド"を見つける
    結果はデータベースから得た結果です
    この構造体はnestedashと呼ばれます.
    なぜ我々はこのような入れ子のハッシュをやっている
    ブログが新しい更新プログラムや挿入や削除操作がキャッシュされた結果を削除した場合、我々は言う必要があります.キャッシュされた結果は古いものであり、新しい操作のいずれかで更新されません.

    今すぐコードに戻る。


    mongoose.Query.prototype.exec = async function(){
        const collectionName = this.mongooseCollection.name;
    
        if(this.cacheMe){   
          // You can't insert json straight to redis needs to be a string 
    
            const key = JSON.stringify({...this.getOptions(),
                 collectionName : collectionName, op : this.op});
            const cachedResults = await redis.HGET(collectionName,key);
    
          // getOptions() returns the query and this.op is the method which in our case is "find" 
    
            if (cachedResults){
              // if you found cached results return it; 
                const result = JSON.parse(cachedResults);
                return result;
            }
         //else 
        // get results from Database then cache it
            const result = await exec.apply(this,arguments); 
    
            redis.HSET(collectionName, key, JSON.stringify(result) , "EX",this.cacheTime);
           //Blogs - > {op: "find" , ... the original query} -> result we got from database
            return result;
        }
    
        clearCachedData(collectionName, this.op);
        return exec.apply(this,arguments);
    }
    
    私が更新、挿入または削除の場合、キャッシュされたデータをクリアする必要があると言った部分を覚えておいてください.

    キャッシュデータをクリアする


    async function clearCachedData(collectionName, op){
        const allowedCacheOps = ["find","findById","findOne"];
        // if operation is insert or delete or update for any collection that exists and has cached values 
        // delete its childern
        if (!allowedCacheOps.includes(op) && await redis.EXISTS(collectionName)){
            redis.DEL(collectionName);
        }
    }
    

    予想結果


    はるかに高速クエリを検索します.

    キャッシュ

  • 大きなデータをキャッシュしない
    あなたがデータを20 MBまたは100 MBの価値を返す検索クエリがある場合は、あなたのアプリケーション全体を減速されます想像してください.
  • は、多くのトラフィックを得ない要求をキャッシュしないでください、そして、それはあなたのアプリケーションに非常に依存しています.
  • ユーザーやトランザクションのような重要なデータをキャッシュしないでください.
  • 最終ノート


  • My redis setup .
  • cachetime paramterは1時間のデフォルトを置くオプションですが、あなたが望むようにそれを編集することができます、私は1または2日をお勧めします.