15

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

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

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

redisClient = redis.createClient();

在选择新数据库时,我使用带有额外预警回调的 select 命令,所以我的 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中的每个数据库使用单独的 redisClients有多合理。所以它会像;

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

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

4

5 回答 5

14

正如Carl Zulauf 所说,最好打开 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将已经初始化。

于 2013-01-02T19:12:26.330 回答
11

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

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

于 2012-12-22T21:10:18.140 回答
7

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

我在自己在异步环境中与多个数据库支持作斗争之后这么说。不知不觉中,我访问了 Freenode 上的#redis,并被 Redis 的作者 Salvatore Sanfilippo 提到了以下声明:

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

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

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

于 2013-07-10T14:01:36.223 回答
2

除了为 3 个不同的数据库设置 3 个不同的连接之外,您还可以MULTI/EXEC为此使用 block:

redisClient.multi().select(1).set("my_key_in_db_1","myval").exec()
于 2013-01-02T16:14:24.000 回答
1

为每个数据库使用一个实例是正确的方法。但是,如果您需要重用或限制昂贵的资源(例如数据库连接),那么数据库连接池可能是一个不错的选择。假设我们选择了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);
    });
});
于 2013-01-04T06:14:47.617 回答