如何将redi中的MongoDB文档存储为缓存并通过超时刷新

时间:2014-09-13 20:27:31

标签: node.js mongodb caching redis

我有处理嵌套JSON文档的nodejs应用程序,如下所示:

var post = {
  id: 123,
  title: 'Sterling Archer',    
  comments: [
    {text: 'Comment text', tags: ['tag1', 'tag2', 'tag3']},
    {text: 'Comment test', tags: ['tag2', 'tag5']}
  ]  
};

并将它们存储在MongoDB数据库中。我的文档需要经常更新,但正如您所知,MongoDB由于其性质而在写入时速度非常慢。为了解决这个问题,我决定将文档存储在Redis中并在一段时间内(例如1-2小时后)刷新到MongoDB。

所以这里是我更新方法的代码示例:

var redis_cli = require("redis").createClient();

app.post('/update/:id', function (req, res, next) {

  var id = req.params.id
  redis_cli.get(id, function (err, document) {
      if (err) return next(err);

      // If there is no key, try to get from MongoDB
      if (!document) {
         DocumentModel.findOneByid(id, function (err, document) {
             if (err) return next(err);
             if (!document) return next(new Error("Document with id " + id + " does not exists"));

             // Document in MongoDB, so store in redis
             redis_cli.set(id, JSON.stringify(document), function (err) {
                  if (err) return next(err);

                  updateDocument(document);
             });                    
         });    
      } else {
          updateDocument(JSON.parse(document));
      }

      function updateDocument (document) {
          // Do some updates ...
          document.title = "Updated post title";

          // Store to redis
          redis_cli.set(id, JSON.strinfy(document), function (err) {
              if (err) return next(err);

              // Document updated successful
              return res.status(200).send('OK');
          });              
      }          
  });
});

我的第一个问题是如何考虑我使用文档的方法?我的方法有问题吗?

第二个问题是如何将Redis中的文档刷回mongodb并从redis中删除?我的目的如下:我希望仅在必要时由我的用户以redis格式存储文档,因此如果不使用他们的文档,则应将其存储在MongoDB而不是Redis中。

1 个答案:

答案 0 :(得分:2)

你的方法似乎很合理。

要“刷新”文档,请在Redis中保存已更新的文档ID的排序集,将其分数设置为更新时间戳。定期地,例如每一分钟,在该集合上做一个ZRANGE以获得“旧”(例如,超过一小时前的最后更新)文档ID,并为每个id执行文档的GET,将其写入Mongo,DEL文档和ZREM从有序集。

编辑在pseudo-Node.js中未经测试且完全编写代码示例:

 function updateDocument (document) {
      // Do some updates ...
      document.title = "Updated post title";

      // Store to redis
      multi = redis_cli.multi();
      multi.set(id, JSON.strinfy(document);
      multi.zadd('last_update', time(), id);
      multi.exec(), function (err, replies) {
          if (err) return next(err);

          // Document updated successful
          return res.status(200).send('OK');
      });              
  }

  // call this function periodically, e.g. every minute or so
  function flushOldDocuments () {
      fromTime = time()-3600;
      while (redis_cli.zcount('last_update', '-inf', fromTime) > 0) {
          id = redis_cli.zrangebyscore('last_update', '-inf', fromTime, false, 0, 1); // no scores, offset 0, limit 1 -> get the oldest document
          redis_cli.watch(id);
          Mongo.write(JSON.parse(redis_cli.get(id))); // or something like that
          multi = redis_cli.multi();
          multi.zrem('last_update', id);
          multi.del(id);
          multi.exec(), function(err, replies) {
              // if the watch fails the exec, no harm done and the document will be flushed in an hour
              ...
          };
      };
  }