首页 > 解决方案 > 将redis.get分组2ms,然后由mget执行

问题描述

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

在监视 newrelic 时,我得到 200MS 平均redis.get时间,为了优化这一点,我在 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获得时间吗?上述问题还有其他解决方案吗?

谢谢

标签: node.jsredis

解决方案


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

MGET的时间复杂度为

O(N) 其中 N 是要检索的键的数量。

GET时间复杂度为

O(1)

就您的场景中的时间复杂度而言,这使这两种场景具有相同的最终结果。使用 MGET 进行批量请求可以为 IO 带来一些改进,但除此之外,您似乎也遇到了同样的瓶颈。

理想情况下,我会将我的数据分成块,如果可以选择,则以异步方式通过多个 http 请求进行响应。

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

就像是;

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

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

推荐阅读