【问题标题】:Redis error in node.jsnode.js 中的 Redis 错误
【发布时间】:2017-11-30 18:04:40
【问题描述】:

我在 Node.js 中使用 Redis,当部署在实时服务器上时,它开始崩溃并出现以下错误消息:

每秒请求数更多。

at Object.replyToObject [as reply_to_object] (/home/ubuntu/webservices/node_modules/redis/lib/utils.js:7:15)
at RedisClient.handle_reply (/home/ubuntu/webservices/node_modules/redis/index.js:319:23)
at multi_callback (/home/ubuntu/webservices/node_modules/redis/lib/multi.js:79:43)
at Command.callback (/home/ubuntu/webservices/node_modules/redis/lib/multi.js:116:9)
at normal_reply (/home/ubuntu/webservices/node_modules/redis/index.js:726:21)
at RedisClient.return_reply (/home/ubuntu/webservices/node_modules/redis/index.js:824:9)
at JavascriptRedisParser.returnReply (/home/ubuntu/webservices/node_modules/redis/index.js:192:18)
at JavascriptRedisParser.execute (/home/ubuntu/webservices/node_modules/redis/node_modules/redis-parser/lib/parser.js:553:10)
Socket.<anonymous> (/home/ubuntu/webservices/node_modules/redis/index.js:274:27)
emitOne (events.js:116:13)
Socket.emit (events.js:211:7)
addChunk (_stream_readable.js:263:12)
readableAddChunk (_stream_readable.js:250:11)
at Socket.Readable.push (_stream_readable.js:208:10)
at TCP.onread (net.js:594:20)

我已经编写了通用代码来打开和关闭 Redis 连接并尝试重用连接。 (不确定是否是正确的重用方式)。

我正在使用 Redis "^2.7.1" 并在 Ubuntu 上本地安装了 Redis。

我可以进入 Redis 控制台并查看存储的密钥。但不确定为什么它会非常频繁地给出上述错误消息。我正在使用 pm2 模块,所以它在崩溃后会重新启动。

以下是 Node.js 中的 Redis 代码

var Promise = require('bluebird');
var Redis = Promise.promisifyAll(require('redis'));

// Global (Avoids Duplicate Connections)
var redisClient = null;
var redisMultiClient = null;

// Make the below functions as private
function openRedisConnection() {
    if (redisClient && redisClient.connected)
        return redisClient;

    if (redisClient)
        redisClient.end(); // End and open once more

    redisClient = Redis.createClient(6379,process.env.REDIS_URL);
    redisClient.selected_db = 1;
    return redisClient;
}

function openMultiRedisConnection() {
    if (redisMultiClient && redisMultiClient._client.connected) {
        redisMultiClient._client.selected_db = 0;
        return redisMultiClient;
    }

    if (redisMultiClient)
        redisMultiClient.quit(); // End and open once more

    redisMultiClient = Redis.createClient(6379,process.env.REDIS_URL).multi();
    redisMultiClient._client.selected_db = 0;
    return redisMultiClient;
}

function getExpiryTime(key) {
    return 120; // testing
}


module.exports = {
    /**
     * Get Key-Value Pair
     */
    getRedisValue: function (keys) {
        return openRedisConnection().mgetAsync(keys);
    },
    /**
     * Set Key-Value Pair
     */
    setRedisValue: function (key, value) {
        return openRedisConnection()
            .setAsync(key, value, 'EX', getExpiryTime(key))
            .then(function (result) {
                return Promise.resolve(result);
            });
    },

    getV2MultiRedisValue: function (keyList) {
        let redisMultiClientObj = openMultiRedisConnection();
        redisMultiClientObj._client.selected_db = 2;

        redisMultiClientObj.hgetallAsync(keyList);

        return redisMultiClientObj.execAsync()
            .then(function (results) {
                return Promise.resolve(results);
            });
    },

    setV2MultiRedisValue: function (key, redisList) {
        let expiryTime = getExpiryTime(key);
        let redisMultiClientObj = openMultiRedisConnection();
        redisMultiClientObj._client.selected_db = 2;

        for (let item of redisList) {
            redisMultiClientObj.hmsetAsync(item.key, item.value);
            redisMultiClientObj.expireAsync(item.key, expiryTime);
        }
        return redisMultiClientObj.execAsync()
        .then(function (results) {
            return Promise.resolve(results);
        });
    }
};

【问题讨论】:

    标签: javascript node.js redis node-redis


    【解决方案1】:

    client.multi([commands]) 没有打开多连接,只是指出因为函数openMultiRedisConnection 具有误导性。

    你使用了多个错误,每个参考

    client.multi([commands])

    MULTI 命令排队,直到发出 EXEC,然后所有 命令由 Redis 以原子方式运行。 node_redis中的接口是 通过调用 client.multi() 返回一个单独的 Multi 对象。如果有的话 命令无法排队,所有命令都回滚并且没有命令执行 要执行(有关更多信息,请查看交易)。

    Multi 返回一个单独的对象,在调用.exec 后再次使用它不是很好。

    我不知道为什么您需要更多的数据库,但是您正在使用 selected_db 和全局客户端变量更改数据库,这很糟糕!并可能导致许多问题!(数据不一致、冲突等)。 您可以使用client.select(callback) 更改数据库,但这似乎是个坏主意。

    这部分代码没有理由与不这样做完全相同。

     .then(function (result) {
        return Promise.resolve(result);
      });
    

    你应该只使用一个数据库。

       var Promise = require('bluebird');
    var Redis = Promise.promisifyAll(require('redis'));
    
    // Global (Avoids Duplicate Connections)
    var redisClient = [];
    
    
    // Make the below functions as private
    function openRedisConnection( {
        if (redisClient && redisClient.connected)
            return redisClient;
    
        if (redisClient)
            redisClient.end(); // End and open once more
    
        redisClient = Redis.createClient(6379,process.env.REDIS_URL,{"db":1});
    
        return redisClient;
    }
    
    
    function getExpiryTime(key) {
        return 120; // testing
    }
    
    
    module.exports = {
        /**
         * Get Key-Value Pair
         */
        getRedisValue: function (keys) {
            return openRedisConnection().mgetAsync(keys);
        },
        /**
         * Set Key-Value Pair
         */
        setRedisValue: function (key, value) {
            return openRedisConnection()
                .setAsync(key, value, 'EX', getExpiryTime(key));
    
        },
    
        getV2MultiRedisValue: function (keyList) {
    
             let redisClient = openRedisConnection();
    
            //no need to open multi here....
            let multi = redisClient.multi();
    
            multi.hgetallAsync(keyList);
    
            return multi.execAsync();
    
        },
    
        setV2MultiRedisValue: function (key, redisList) {
            let expiryTime = getExpiryTime(key);
            let redisClient = openRedisConnection();
    
            let multi = redisClient.multi();
    
            for (let item of redisList) {
                multi.hmsetAsync(item.key, item.value);
                multi.expireAsync(item.key, expiryTime);
            }
    
            return multi.execAsync();
    
        }
    };
    

    【讨论】:

    • 感谢您的回答.. 1 .then(function (result) { return Promise.resolve(result); });实际上,在解决承诺之前,为了清楚起见,删除了一些业务逻辑,所以这没关系.. 2 不同的数据库需要检查我是否可以合并。 3 多概念让我实施并尽快回复您
    • //这里不需要打开multi....你在getV2MultiRedisValue函数中提到了这条评论并说let multi = redisClient.multi();这是正确的吗?只是感到困惑
    • multi 用于查询和运行多个命令。由于您只执行 hgetallAsync 这只是一个命令,因此不需要 multi
    • Redis 常用于缓存数据,而不是复杂的“业务”逻辑。你到底想合并什么......也许你有一些可以以不同方式运行的逻辑?
    • 感谢我检查了将近 5 天来监控服务器没有发生崩溃。您的代码有效。
    猜你喜欢
    • 2014-08-27
    • 1970-01-01
    • 2012-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-04
    相关资源
    最近更新 更多