node.js - 将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获得时间吗?上述问题还有其他解决方案吗?
谢谢
解决方案
我不是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))
}
推荐阅读
- python - 在 Tensorflow 中重建 Keras 模型
- python - 从单选按钮返回文本
- vue.js - PhpStorm Vuejs 文件移动将 '/types' 添加到 'vuex' 导入语句
- php - Concat 操作与结果的字符串顺序混淆
- asp.net - 上传dotnet项目框架heroku托管时出错
- python - python %logstart 无法存储输入结果
- go - 如何将 Go dep 与 GitLab 子组一起使用
- python - 如何最有效地“推送和移动”numpy数组中的元素?
- ios - 占用内存不断增加,但没有内存泄漏
- reactjs - Reactjs中如何从父组件的事件中调用子组件的方法