INF*_*SYS 3 javascript concurrency node.js
过去1周,我一直面对这个问题,对此我感到困惑。简明扼要地解释问题。
我们有一个内存模型,用于存储预算等值,现在调用API时会产生花费。
然后,我们检查内存中的模型并将支出增加到现有支出中,然后检查预算,如果超出预算,我们将不再接受该模型的任何点击。对于每个调用,我们还将对数据库进行udpate,但这是一个异步操作。
一个简短的例子
api.get('/clk/:spent/:id', function(req, res) {
checkbudget(spent, id);
}
checkbudget(spent, id){
var obj = in memory model[id]
obj.spent+= spent;
obj.spent > obj.budjet // if greater.
obj.status = 11 // 11 is the stopped status
update db and rebuild model.
}
Run Code Online (Sandbox Code Playgroud)
过去效果不错,但现在对于并发请求,我们得到的虚假支出超出了预算,超出了预算,并且在一段时间后停止。我们用j meter模拟了呼叫,并发现了这一点。
据我们所知,节点是异步的,因此在状态更新为11之前,许多线程已经更新了广告系列的支出。
如何为Node.js使用信号量逻辑,以使可变预算与模型同步
更新
db.addSpend(campaignId, spent, function(err, data) {
campaign.spent += spent;
var totalSpent = (+camp.spent) + (+camp.cpb);
if (totalSpent > camp.budget) {
logger.info('Stopping it..');
camp.status = 11; // in-memory stop
var History = [];
History.push(some data);
db.stopCamp(campId, function(err, data) {
if (err) {
logger.error('Error while stopping );
}
model.campMAP = buildCatMap(model);
model.campKeyMap = buildKeyMap(model);
db.campEventHistory(cpcHistory, false, function(err) {
if (err) {
logger.error(Error);
}
})
});
}
});
Run Code Online (Sandbox Code Playgroud)
代码的GIST现在任何人都可以提供帮助
问:是否存在semaphore或等效的NodeJs?
答: 不可以。
问:那么NodeJs用户如何处理比赛条件?
答:从理论上讲,你不应该因为没有thread在javascript。
在深入研究我提出的解决方案之前,我认为对于您来说了解NodeJs工作原理很重要。
因为NodeJs它是由基于事件的体系结构驱动的。这意味着在此Node过程中,将有一个包含所有“待办事项”事件的事件队列。
当event得到pop从队列中,node将执行所有,直到它完成了所需的代码。async运行期间发出的所有呼叫都会与其他呼叫一样产生,events并在队列中排队,event queue直到听到响应并可以再次运行它们为止。
问:那么我该怎么做才能确保一次只能updates对数据库执行一个请求?
答:我相信可以通过多种方法来实现这一目标,但是更简单的方法之一就是使用set_timeoutAPI。
例:
api.get('/clk/:spent/:id', function(req, res) {
var data = {
id: id
spending: spent
}
canProceed(data, /*functions to exec after canProceed=*/ checkbudget);
}
var canProceed = function(data, next) {
var model = in memory model[id];
if (model.is_updating) {
set_timeout(isUpdating(data, next), /*try again in=*/1000/*milliseconds*/);
}
else {
// lock is released. Proceed.
next(data.spending, data.id)
}
}
checkbudget(spent, id){
var obj = in memory model[id]
obj.is_updating = true; // Lock this model
obj.spent+= spent;
obj.spent > obj.budjet // if greater.
obj.status = 11 // 11 is the stopped status
update db and rebuild model.
obj.is_updating = false; // Unlock the model
}
Run Code Online (Sandbox Code Playgroud)
注意:我在这里得到的也是伪代码,因此您可能需要对其进行一些调整。
这里的想法是在模型中有一个标志,以指示a是否HTTP request可以继续执行关键代码路径。在这种情况下,您的checkbudget功能将超越其他。
当请求进入时,检查is_updating标志以查看其是否可以继续。如果是,true则它安排一个事件,将在一秒钟后触发,此“ setTimeout”基本上变成一个事件,并放入node的事件队列中,以供以后处理
稍后触发此事件时,将再次进行检查。这种情况一直持续到is_update标志变为false然后请求继续执行它的工作为止,并is_update在所有关键代码完成后再次设置为false。
这不是最有效的方法,但是它可以完成工作,当性能出现问题时,您始终可以重新访问该解决方案。
| 归档时间: |
|
| 查看次数: |
3515 次 |
| 最近记录: |