【问题标题】:Node & Redis: Redis ClientsNode 和 Redis:Redis 客户端
【发布时间】:2012-12-07 21:54:07
【问题描述】:

假设您在 Redis 中有 多个 db,您希望从中插入和/或删除数据。你有这样的流程;

  • 将数据插入到 DB #1
  • 在第一次插入的 回调 之后做一些事情并将数据插入到 DB #2
  • 在第二次插入的 回调 之后再次做一些事情,最后将数据插入到 DB #3

我使用一个名为 redisClient 的变量,它基本上被创建为;

redisClient = redis.createClient();

在选择新数据库时,我使用 select 命令和额外的预警回调,所以我的选择命令就像;

redisClient.select(1, function(err) {
  //Some programming logic (Insertion, deletion and stuff)
  redisClient.select(2, function(err) {
    //Do some additional programming logic (Insertion, deletion and stuff)
  }
});

然而,事情总是变得复杂。我想指出 redisClient 变量只分配了一次,然后在整个应用程序中使用。现在我想知道,为我在 Redis 中拥有的每个 DB 使用 单独的 redisClients 会有多合理。所以它会像;

redisClientForDB1 = redis.createClient();
redisClientForDB2 = redis.createClient();
redisClientForDB3 = redis.createClient();

我想知道这是否合理,或者对于将接收 每秒 4K 请求并即将进入生产模式的应用程序来说,这是否是正确的方法。该模型可能面临哪些问题

【问题讨论】:

    标签: javascript performance api node.js redis


    【解决方案1】:

    就像Carl Zulauf said一样,最好打开3个不同的连接(每个DB一个):

    redisClient = {
      DB1: redis.createClient(),
      DB2: redis.createClient(),
      DB3: redis.createClient()
    };
    

    最好在服务器初始化期间打开所有连接一次:

    async.parallel([
      DB1.select.bind(DB1, 1),
      DB2.select.bind(DB2, 2),
      DB3.select.bind(DB3, 3)
    ], next);
    

    所以,在您创建 redisClient 对象并对其进行初始化后,您可以使用它来处理您的所有 redis 操作。

    如果您以这种方式使用 redis,节点将为每个节点进程打开 3 个(且仅 3 个)连接。


    注意将它们全部放在一个节点模块中也是一个好主意:

    module.exports = {
      DB1: redis.createClient(),
      DB2: redis.createClient(),
      DB3: redis.createClient(),
      init: function(next) {
        var select = redis.RedisClient.prototype.select;
        require('async').parallel([
          select.bind(this.DB1, 1),
          select.bind(this.DB2, 2),
          select.bind(this.DB3, 3)
        ], next);
      }
    };
    

    然后你就可以通过调用一次init函数来初始化你所有的redis连接(因为节点缓存require调用):

    require('./lib/my_redis').init(function(err) {
      if (err) throw err;
      server.listen();
    });
    

    那么当require('./lib/my_redis').DB1.set('key','val') 将在你的任何模块中被调用时,DB1 将已经被初始化。

    【讨论】:

      【解决方案2】:

      对 3 个不同的数据库使用 3 个连接是正确的方法。打开其他连接会产生开销,但开销非常小。

      如果有数百个打开的连接,开销就会开始成为问题。我不确定您将运行多少个应用实例,但猜测每个进程只有 3 个连接,您不会得到任何接近有问题的数字。

      【讨论】:

      • 是的!为每个连接使用单独的客户端是可行的方法:)
      【解决方案3】:

      如果 Google 将您带到这里,请帮自己一个忙:不要使用多数据库支持。使用命名空间键或多个 redis 实例。

      我是在自己在异步环境中为多个数据库支持而苦苦挣扎之后才这么说的。不知不觉中,我访问了 Freenode 上的#redis,并被 Redis 的作者 Salvatore Sanfilippo 引用了以下声明:

      我认为 Redis 多个数据库错误是我在 Redis 中最糟糕的决定 设计...我希望 在某些时候我们可以完全放弃对多个数据库的支持,但我认为 可能为时已晚,因为有很多人依赖这个 他们工作的特色。

      https://groups.google.com/d/msg/redis-db/vS5wX8X4Cjg/8ounBXitG4sJ

      在使用作者最后悔的功能之前,您真的要三思而后行。

      【讨论】:

      • 使用此功能有哪些实际问题?
      • 您必须启动整个服务作为对 DB 选择命令的回调。让 main 成为配置回调很尴尬,特别是当多个配置元素以这种方式工作时。一方面,它不可能在配置错误时快速失败。
      【解决方案4】:

      您也可以使用 MULTI/EXEC 块来代替为 3 个不同的数据库设置 3 个不同的连接:

      redisClient.multi().select(1).set("my_key_in_db_1","myval").exec()
      

      【讨论】:

        【解决方案5】:

        为每个数据库使用一个实例是正确的方法。但是,如果您需要重用或限制昂贵的资源(例如数据库连接),那么数据库连接池可能是一个不错的选择。假设我们选择generic-pool(node.js 的通用池化解决方案),您可以这样编码:

        // Step 1 - Create pool using a factory object
        var mysql= require('mysql'),
            generic_pool = require('generic-pool');
        
        var pool = generic_pool.Pool({
            name: 'mysql pool 1',
            min: 1,
            max: 50,
            idleTimeoutMillis : 30000,
            create   : function(callback) {
                var Client = mysql.Client;
                var c = new Client();
                c.user     = 'myusername';
                c.password = 'mypassword';
                c.database = 'mydb';
                c.connect();
        
                callback(null, c);
            },
            destroy  : function(client) { client.end(); }
        });
        
        // Step 2 - Use the pool in your code to acquire/release resources
        pool.acquire(function(err, client) {
            if (err) {
                // handle error
                return res.end("CONNECTION error: " + err);
            }
            client.query("select * from foo", [], function() {
                // return object back to pool
                pool.release(client);
            });
        });
        

        【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-17
        • 2020-04-10
        • 1970-01-01
        • 2023-03-09
        • 2012-02-22
        • 2015-05-04
        • 1970-01-01
        • 2019-04-28
        相关资源
        最近更新 更多