我是API用户,我只能获得数量有限的高流量网站请求(~1k并发访问者)。为了保存API请求,我想缓存不太可能改变的特定请求的响应。
但是我想至少每15秒刷新一次redis键(API响应)。我想知道最好的办法是什么?
我的想法:
您对此用例有何建议?
我的控制器代码:
function players(req, res, next) {
redisClient.getAsync('leaderboard:players').then((playersLeaderboard) => {
if(!playersLeaderboard) {
// We need to get a fresh copy of the playersLeaderboard
}
res.set('Cache-Control', 's-maxage=10, max-age=10')
res.render('leaderboards/players', {playersLeaderboard: playersLeaderboard})
}).catch((err) => {
logger.error(err)
})
}
答案 0 :(得分:1)
只需在node.js服务器启动时获取并缓存数据,然后设置15秒的间隔以获取新数据并更新缓存。避免将TTL用于此用例。
function fetchResultsFromApi(cb) {
apiFunc((err, result) => {
// do some error handling
// cache result in redis without ttl
cb();
});
}
fetchResultsFromApi(() => {
app.listen(port);
setInterval(() => {
fetchResultsFromApi(() => {});
}, 15000);
}
<强>优点:强>
<强>缺点:强>
答案 1 :(得分:1)
我想这更像是一个架构问题,而不是典型的“帮助我的代码无法正常工作”。
让我解释一下你的要求。
问:我想缓存一些不太可能改变的HTTP请求的响应,我希望这些缓存的响应每15秒刷新一次。有可能吗?
A:是的,你会感谢Javascript
是单线程的,所以它会非常直接。
这里有一些基础知识。 NodeJS
是一个事件驱动的框架,这意味着在1个时间点它将只执行一段代码,直到完成为止。
如果在此过程中遇到任何aysnc
来电,它会调用它们并向event-loop
添加一个事件,以便在收到回复时说“callback
”。当代码例程完成后,它将从队列中弹出下一个事件来运行它们。
基于这些知识,我们知道我们可以通过构建function
来实现此目的,以便只在update
cached-responses
每次到期时发出1次异步调用。如果异步调用已经在运行,那么只需将其回调函数放入队列即可。这样您就不会进行多次异步调用来获取新结果。
我不熟悉async
模块,因此我使用promises
提供了一个伪代码示例。
伪码:
var fetch_queue = [];
var cached_result = {
"cached_result_1": {
"result" : "test",
"expiry" : 1501477638 // epoch time 15s in future
}
}
var get_cached_result = function(lookup_key) {
if (cached_result.hasOwnProperty(lookup_key)) {
if (result_expired(cached_result[lookup_key].expiry)) {
// Look up cached
return new Promise(function (resolve) {
resolve(cached_result[lookup_key].result);
});
}
else {
// Not expired, safe to use cached result
return update_result();
}
}
}
var update_result = function() {
if (fetch_queue.length === 0) {
// No other request is retrieving an updated result.
return new Promise(function (resolve, reject) {
// call your API to get the result.
// When done call.
resolve("Your result");
// Inform other requests that an updated response is ready.
fetch_queue.forEach(function(promise) {
promise.resolve("Your result");
})
// Compute the new expiry epoch time and update the cached_result
})
}
else {
// Create a promise and park it into the queue
return new Promise(function(resolve, reject) {
fetch_queue.push({
resolve: resolve,
reject: reject
})
});
}
}
get_cached_result("cached_result_1").then(function(result) {
// reply the result
})
注意:顾名思义,代码不是实际工作解决方案,但概念就在那里。
值得注意的是,setInterval
是一种方法但它不能保证该函数将在15秒标记时被完全调用。 API仅确保在预期时间之后发生某些事情。
虽然建议的解决方案将确保只要cached result
已过期,下一个查找的人就会发出请求,以下请求将等待初始请求返回。