Node.js 使用redis作为restapi用户的缓存(以保存Api请求)
我是一名API用户,对于高流量网站(约1k并发访问者),我的可用请求数量有限。为了保存API请求,我想缓存不太可能更改的特定请求的响应 但是,我希望至少每15秒刷新一次这个redis密钥(API响应)。我想知道最好的方法是什么 我的想法:Node.js 使用redis作为restapi用户的缓存(以保存Api请求),node.js,rest,api,caching,redis,Node.js,Rest,Api,Caching,Redis,我是一名API用户,对于高流量网站(约1k并发访问者),我的可用请求数量有限。为了保存API请求,我想缓存不太可能更改的特定请求的响应 但是,我希望至少每15秒刷新一次这个redis密钥(API响应)。我想知道最好的方法是什么 我的想法: function players(req, res, next) { redisClient.getAsync('leaderboard:players').then((playersLeaderboard) => { if(!p
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)
})
}
- 我认为TTL字段对于这个场景来说很方便。只需将此键的TTL设置为15秒。当我查询这个密钥而它不存在时,我会使用API再次请求它问题:由于这是一个高流量的网站,在收到API的响应之前,我预计会收到大约20-30个请求,这将导致在几毫秒内向API发出20-30个请求。因此,我需要“暂停”所有传入请求,直到有API响应
- 我的第二个想法是每隔15秒刷新一次钥匙。我可以设置一个每15秒运行一次的后台任务,或者根据页面请求,如果密钥需要刷新,我可以检查控制器。我更喜欢最后一个想法,但因此我需要维护redis key age,这似乎非常昂贵,而且不是内置功能
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)
})
}
只需在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);
}
优点:
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)
})
}
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)
})
}
只需在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);
}
优点:
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)
})
}
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)
})
}
我想这比那些典型的“帮助我的代码不工作”更像是一个架构问题 让我解释一下你的要求 Q:我希望缓存一些不太可能更改的HTTP请求的响应,并且希望这些缓存的响应每15秒刷新一次。可能吗 A:是的,你要感谢
Javascript
是单线程的,所以它将非常简单
这里有一些基础知识NodeJS
是一个事件驱动的框架,这意味着在一个时间点,它将只执行一段代码,直到完成为止
如果在此过程中遇到任何aysnc
调用,它将调用它们并向event循环添加一个事件
,在收到响应时说“callback
”。代码例程完成后,它将从队列中弹出下一个事件来运行它们
基于这些知识,我们知道我们可以通过构建一个函数
来实现这一点,该函数在缓存响应每次过期时只对更新
发出一个异步调用。如果异步调用已经在运行,那么只需将它们的回调函数放入队列。这样,您就不会执行多个异步调用来获取新结果
我不熟悉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只确保在预期时间之后会发生某些事情
然而,建议的解决方案将确保只要缓存的结果过期,下一个查找它的人就会发出请求,而下面的请求将等待初始请求返回。我想这更像是一个架构问题,而不是典型的“帮助我的代码不工作”类型
让我解释一下你的要求
Q:我希望缓存一些不太可能更改的HTTP请求的响应,并且希望这些缓存的响应每15秒刷新一次。可能吗
A:是的,你要感谢Javascript
是单线程的,所以它将非常简单
这里有一些基础知识NodeJS
是一个事件驱动的框架,这意味着在一个时间点,它将只执行一段代码,直到完成为止
如果在此过程中遇到任何aysnc
调用,它将调用它们并向event循环添加一个事件
,在收到响应时说“callback
”。代码例程完成后,它将从队列中弹出下一个事件来运行它们
基于这些知识,我们知道可以通过构建函数