Node & Redis: клиенты Redis
Предположим, что у вас есть multiple db в Redis, с которого вы хотели бы вставить и/или удалить данные. У вас такой поток;
- Вставьте данные в DB # 1
- После первой вставки callback выполните некоторые действия и вставьте данные в DB # 2
- После второй вставки callback снова выполните некоторые вещи и, наконец, вставьте данные в 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 была назначена только один раз и позже на протяжении всего приложения. Теперь мне было интересно, насколько разумно использовать отдельные redisClients для каждого DB, которые у меня есть в Redis. Так было бы:
redisClientForDB1 = redis.createClient();
redisClientForDB2 = redis.createClient();
redisClientForDB3 = redis.createClient();
Мне было интересно, было бы это разумно или это был бы правильный способ для приложения, которое получит 4K запросов в секунду и собирается перейти в производственный режим. С какими проблемами может столкнуться эта модель?
Ответы
Ответ 1
Так же, как Карл Зулауф сказал, лучше всего открыть 3 разных соединения (по одному на БД):
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 таким образом, node откроет 3 (и только 3) соединения для процесса node.
N.B. Также рекомендуется добавить все в один модуль node:
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);
}
};
Затем вы сможете инициализировать все свои redis-соединения, вызвав функцию init
один раз (потому что вызов node caching 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.
Я говорю об этом после того, как я сам боролся с поддержкой нескольких БД в асинхронной среде. В конце концов, я посетил #redis на Freenode и был упомянут в следующем заявлении автора Redis, Сальваторе Санфилиппо:
Я рассматриваю Redis несколько ошибок базы данных, мое худшее решение в Redis дизайн вообще... Надеюсь, что в какой-то момент мы можем отказаться от поддержки нескольких БД, но я думаю вероятно, слишком поздно, поскольку существует ряд людей, полагающихся на это для их работы.
https://groups.google.com/d/msg/redis-db/vS5wX8X4Cjg/8ounBXitG4sJ
Вы действительно хотите дважды подумать, прежде чем полагаться на эту функцию, о которой автор сожалеет больше всего.
Ответ 4
Вместо трех разных соединений для 3 разных БД вы можете использовать для этого блок MULTI/EXEC
:
redisClient.multi().select(1).set("my_key_in_db_1","myval").exec()
Ответ 5
Использование одного экземпляра для каждой базы данных - правильный подход. Но если вам нужно повторно использовать или дросселировать такие дорогостоящие ресурсы, как соединения с базой данных, то пул соединений с базой данных может быть хорошим выбором. Скажем, мы выберем общий пул (общее решение для пула для 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);
});
});