mongodb(mongoose-redis-cache)

在传统的项目中,我们经常会用到缓存来优化数据库的读取,比如java中,我们利用spring的AOP能力,在读写数据库前增加对缓存的操作。

在node与mongodb的项目中也仍然会存在类似问题,本文参考了mongoose-redis-cache这个插件。

https://github.com/conancat/mongoose-redis-cache

该插件还不太完善,但基本的思路是很简单的,初始化一个redis客户端,然后重写mongoose的exec方法,将exec的参数设置为redis的key,将数据库返回的结果设置为对应的value。

每次操作时优先读取redis。

代码如下:

// Generated by CoffeeScript 1.5.0
var mongooseRedisCache, redis, _;

redis = require("redis");

_ = require("underscore");

mongooseRedisCache = function(mongoose, options, callback) {
  var client, host, pass, port, redisOptions;
  if (options == null) {
    options = {};
  }
  host = options.host || "";
  port = options.port || "";
  pass = options.pass || "";
  redisOptions = options.options || {};
  mongoose.redisClient = client = redis.createClient(port, host, redisOptions);
  if (pass.length > 0) {
    client.auth(pass, function(err) {
      if (callback) {
        return callback(err);
      }
    });
  }

//这里做了改动,原来是execFind,在我当前的Mongoose版本下无法使用 mongoose.Query.prototype._exec
= mongoose.Query.prototype.exec; mongoose.Query.prototype.exec = function(callback) { var cb, expires, fields, key, model, query, schemaOptions, self; self = this; model = this.model; query = this._conditions; options = this._optionsForExec(model); fields = _.clone(this._fields); schemaOptions = model.schema.options; expires = schemaOptions.expires || 60; if (!schemaOptions.redisCache && options.lean) { return mongoose.Query.prototype._exec.apply(self, arguments); } key = JSON.stringify(query) + JSON.stringify(options) + JSON.stringify(fields); cb = function(err, result) { var docs; if (err) { return callback(err); } if (!result) { return mongoose.Query.prototype._exec.call(self, function(err, docs) { var str; if (err) { return callback(err); } str = JSON.stringify(docs); client.set(key, str); client.expire(key, expires); return callback(null, docs); }); } else { docs = JSON.parse(result); return callback(null, docs); } }; client.get(key, cb); return this; }; }; module.exports = mongooseRedisCache;

写测试用例如下:

var mongoose = require(‘mongoose‘);

var async = require(‘async‘);
var mongooseRedisCache = require("mongoose-redis-cache");
mongooseRedisCache(mongoose);
var Schema = mongoose.Schema;

mongoose.connect(‘mongodb://localhost/cachetest‘);

var user = new Schema({
    username:{
        type:String,
        index:true
    },
    password:String
});

user.set(‘redisCache‘, true);

var userModel = mongoose.model(‘user‘, user);

var entity = new userModel({
    username:‘fredric‘,
    password:‘sinny‘
});

var users = [];
for(var i = 0; i < 1000; i++){
    users.push({
        username:‘fredric‘ + i,
        password:‘sinny‘ + i
    });
}

function testCache(){

    function datainit(item,cb){
        var entity = new userModel(item);
        entity.save(function(err){
            cb(err);
        });
    }
    
    async.mapSeries(users, datainit, function(err, results){
        
        console.log(‘datainit finished‘);
        
        var timestamp = new Date().valueOf();
        
        var round = [];
        for(var i = 0; i < 2000; i++){
            round.push(i);
        }
        
        //利用缓存
        function test(item,cb){
            query = userModel.find({‘username‘:‘fredric101‘});
            query.lean();
            query.exec(function(err, result){
                cb(err);
            });
        }
        
        
        //不利用缓存
        function test_nocache(item,cb){
            query = userModel.find({}).setOptions({nocache: true});
            query.where("username", "fredric101");
            query.exec(function(err, result){
                cb(err);
            });
        }
        
        async.mapSeries(round, test_nocache, function(err, results){
            console.log(new Date().valueOf() - timestamp);
        });
    });    
}
testCache();

测试结果还是比较明显的,在我本地笔记本上(安装redis + mongodb),上述测试用例执行:

1、无缓存、无索引:21501ms

2、无缓存、有索引:1966ms

3、有缓存、有索引:281ms

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。