node.js - 将redis.get分组2ms,然后通过mget执行

标签 node.js redis

我的应用程序进行大约 50 个 redis.get 调用来服务单个 http 请求,它每天服务数百万个请求,并且应用程序在大约 30 个 pod 上运行。

当监视 newrelic 时,我的平均 redis.get 时间为 200MS,为了优化这一点,我在 Nodejs 中编写了一个简单的管道系统,它只是 redis.get 的包装器> 它将所有请求推送到队列中,然后使用 redis.mget 执行队列(批量获取所有键)。

以下是代码片段:


class RedisBulk {
  constructor() {
    this.queue = [];
    this.processingQueue = {};
    this.intervalId = setInterval(() => {
      this._processQueue();
    }, 5);
  }
  clear() {
    clearInterval(this.intervalId);
  }
  get(key, cb) {
    this.queue.push({cb, key});
  }

  _processQueue() {
    if (this.queue.length > 0) {
      let queueLength = this.queue.length;
      logger.debug('Processing Queue of length', queueLength);
      let time = (new Date).getTime();
      this.processingQueue[time] = this.queue;
      this.queue = []; //empty the queue

      let keys = [];
      this.processingQueue[time].forEach((item)=> {
        keys.push(item.key);
      });
      global.redisClient.mget(keys, (err, replies)=> {
        if (err) {
          captureException(err);
          console.error(err);
        } else {
          this.processingQueue[time].forEach((item, index)=> {
            item.cb(err, replies[index]);
          });
        }
        delete  this.processingQueue[time];
      });
    }
  }
}

let redis_bulk = new RedisBulk();

redis_bulk.get('a');
redis_bulk.get('b');
redis_bulk.get('c');
redis_bulk.get('d');

我的问题是:这是一个好方法吗?它对优化redis获取时间有帮助吗?对于上述问题还有其他解决方案吗?

谢谢

最佳答案

我不是 Redis 专家,但从文档来看;

MGET 的时间复杂度为

O(N) where N is the number of keys to retrieve.

并且GET的时间复杂度为

O(1)

这使得两种场景在时间复杂度方面达到相同的最终结果。使用 MGET 进行批量请求可以为 IO 带来一些改进,但除此之外,您似乎还面临着相同的瓶颈。

理想情况下,我会将数据分割成 block ,通过异步方式通过多个 http 请求进行响应(如果可以的话)。

或者,您可以尝试使用 promise.all() 调用 GET 来并行运行 GET 请求,以满足您需要的所有 GET 调用。

类似于;

const asyncRedis = require("async-redis");
const client = asyncRedis.createClient();

function bulk() {
  const keys = [];
  return Promise.all(keys.map(client.get))
}

关于node.js - 将redis.get分组2ms,然后通过mget执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58747784/

相关文章:

node.js - AWS Lambda,API 网关返回格式错误的 Lambda 代理响应,502 错误

node.js - 无法在 Bundler.transformFile 读取未定义的属性(读取 'transformFile')

python - Celery/Redis : redis. 异常。ResponseError: 'set' 命令的参数数量错误

node.js - 为什么 session 存储有静态超时/maxAge

node.js - 使用NPM和 Node Supervisor

javascript - 强制 javascript 变量作为 "value"传递

node.js - 如何将大量 JSON 数据导出到 Excel 文件

redis - 在 Redis 的单个命令中使用带 TTL 的 RPUSH

ruby - 如何将 redis 作为 rakefile 任务启动

php - 为什么我应该关闭或保持 Redis 连接打开?