简体   繁体   English

Node&Redis:Redis客户端

[英]Node & Redis: Redis Clients

Assume you have multiple db's in Redis you would like to insert and/or remove data from. 假设您在Redis中有多个数据库,您想插入和/或删除数据。 You have a flow like; 你有一个流动;

  • Insert data to DB #1 将数据插入DB#1
  • After the first insertion's callback do some stuff and insert data to DB #2 在第一次插入后, 回调执行一些操作并将数据插入到DB#2中
  • After the second insertion's callback do some stuff again and finally insert data to DB #3 在第二次插入后, 回调再次执行一些操作,最后将数据插入到DB#3中

I use one variable called redisClient that is basically created as; 我使用一个名为redisClient的变量,基本上创建为;

redisClient = redis.createClient();

And while selecting a new DB, I use select command with the extra pre-caution callback, so my select command is like; 虽然选择一个新的数据库,我用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)
  }
});

However things get constantly mix. 然而事情变得不断混合。 I would like to note that the redisClient variable has been assigned only once and later on used throughout the entire application. 我想要注意的是,redisClient变量只被分配了一次,后来在整个应用程序中使用。 Now I was wondering, how reasonable would it be to use seperate redisClients for each DB I have in Redis. 现在我想知道,对Redis中的每个数据库使用单独的redisClients是多么合理。 So it would be like; 所以它会是这样的;

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

I was wondering would it be reasonable, or would it be a right way for an application that will receive 4K requests per sec and about to go to the production mode. 我想知道它是否合理,或者对于每秒接收4K请求并即将进入生产模式的应用程序来说这是一种正确的方法。 What issues this model might face? 这个型号可能面临哪些问题

Just as Carl Zulauf said , it's best to open 3 different connections (one per DB): 正如Carl Zulauf所说 ,最好打开3个不同的连接(每个DB一个):

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

It's best to open all connections once during the initialization of your server: 在服务器初始化期间最好打开所有连接一次:

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

So, after you created redisClient object and initialized it you can use it to handle all your redis operations. 因此,在创建redisClient对象并初始化它之后,您可以使用它来处理所有redis操作。

If you'll use redis this way node will open 3 (and only 3) connections per node process. 如果您将以这种方式使用redis,则节点将为每个节点进程打开3个(且仅3个)连接。


NB It's also a good idea to put it all into one node module: NB将它全部放入一个节点模块也是一个好主意:

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);
  }
};

Then you'll be able to initialize all your redis connections by calling init function once (because node caching require calls): 然后,您将能够通过调用init函数初始化所有redis连接(因为节点缓存require调用):

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

Then when require('./lib/my_redis').DB1.set('key','val') will be called in any of your modules DB1 will be already initialized. 然后当require('./lib/my_redis').DB1.set('key','val')将在你的任何模块中调用DB1将被初始化。

Using 3 connections for 3 different databases is the correct approach. 对3个不同的数据库使用3个连接是正确的方法。 There is overhead for having additional connections open, but that overhead is very small. 打开额外连接会产生开销,但开销非常小。

With something like hundreds of open connections the overhead would start to be a problem. 有了数百个开放连接,开销就会成为一个问题。 I'm not sure how many instances of your app you will run but guessing at just 3 connections per process you won't get anywhere near problematic numbers. 我不确定您将运行多少个应用程序实例,但每个进程只猜测3个连接,您将无法获得有问题的数字。

If Google brought you here, do yourself a favour: don't use multiple DB support. 如果谷歌把你带到这里,请帮个忙:不要使用多个数据库支持。 Use namespaced keys or multiple redis instances. 使用命名空间密钥或多个redis实例。

I say this after having struggled with multiple DB support in an async environment myself. 在我自己在异步环境中努力解决多个数据库支持之后,我这样说了。 At wits end, I visited #redis on Freenode and was referred to the following statement by Redis' author, Salvatore Sanfilippo: 最后,我访问了Freenode上的#redis,并参考了Redis的作者Salvatore Sanfilippo的以下声明:

I consider Redis multiple database errors my worst decision in Redis design at all... I hope that at some point we can drop the multiple DBs support at all, but I think it is probably too late as there is a number of people relying on this feature for their work. 我认为Redis的多个数据库错误是我在Redis设计中最糟糕的决定...我希望在某些时候我们可以放弃多个DB支持,但我认为可能为时已晚,因为有很多人依赖这个功能对他们的工作。

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

You really want to think twice before relying on the feature the author regrets the most. 你真的想依靠笔者感到遗憾的是大部分功能之前,要三思而后行。

您可以使用MULTI/EXEC块来代替3个不同DB的3个不同连接:

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

Using one instance for each database is the correct approach. 为每个数据库使用一个实例是正确的方法。 But if you need to reuse or throttle expensive resources such as database connections, then a database connection pool could be a good choice. 但是,如果您需要重用或限制昂贵的资源(如数据库连接),那么数据库连接池可能是一个不错的选择。 Let's say we choose generic-pool (a generic pooling solution for node.js), you can code like this: 假设我们选择泛型池 (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);
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM