我对Node.js很陌生。 我正在基于express编写节点服务器。 我的服务器收到http请求,请求需要由第三方处理。此过程可能需要几秒钟。
由于节点的非阻塞I / O特性,我无法保证任何处理顺序,而我需要对每个用户/客户端强加顺序处理,这意味着我无法开始处理某个用户的请求,直到先前的请求该用户完成。 具体而言,该解决方案要求:
我想出的解决方案是对每个用户使用fifo队列:
“任务”实际上是将请求发送给第三方进行进一步处理。
我正在想象一个user.id->队列的映射,我有几个问题:
更新 这是一个示例:
想象一下两种类型的请求-存款和全部提款,每种请求都需要花费几秒钟的时间来执行。用户可以在每个存款请求中存入不同的金额,而“全部提取”只是在用户帐户中提取当前金额。 如果用户执行以下操作:。
调用全部提款时,应该总共返回100。 为了提供正确的响应,只有在前一个请求完全完成后才能处理每个请求。 如果第三次存款需要5秒钟,而“全提”(在之后执行)需要1秒钟,那么如果我们不等到存款完成后,用户很有可能会得到70而不是100。为了避免这种情况,我需要依次执行请求,并且还要等一个完成后再执行下一个。
答案 0 :(得分:0)
好的。因此,我将在这里尝试尽可能直接,因为这确实是一个常见的体系结构问题。简而言之,如果我理解正确,您的问题是:
天生是节点异步的,我该如何处理竞赛条件?。
您仍然可以想到什么是正常的解决方案,推荐是这种情况:
每种模式都试图实现与保持数据完整性相同的目的。由于技术和服务种类繁多,因此不可能推荐或指示实现神圣 圣杯解决方案的正确方法(我个人对此表示反对)。
我可以提供的是我如何考虑到简单的银行存款/提款方案来解决该问题。
我将使用带有锁定(乐观)模式的快速访问/写入数据库,例如dynamodb: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBMapper.OptimisticLocking.html并重试该操作,直到成功。
const update = (params)=>{
//considering all checks and sanitazions and every security measure
var params = { //data };
var documentClient = new AWS.DynamoDB.DocumentClient();
documentClient.update(params, function(err, data) {
if (err) {
console.log(err);
return update(params); //recursive, prone to errors ofc //retries a must
} else {
console.log(data);
return data
}
});
}
//express
const route.get('/operation', async (req,res)=>{
update(req.body)
});
Correct way to use DynamoDB Optimistic Locking(JAVA)
更细粒度
或者我可以通过手动将数据库行的状态编辑为'LOCKED'并将其作为操作添加到另一个表中并向事件发送信号来管理Node中的事件。每次完成执行更新功能后,发射器都会发出信号订阅了上传值(websockets):
//orm way
const checkQueue= async ()=>{
const {id} = await Account.findAll({order:'DESC', limit:1})
Account.update({amount: amount + newTransaction}, {where:{id})
.then((success)=>{
operation.emit('TRANSACTIONS_QUEUE'); //would call checkQueue again
res.json({state...})
//we would have previous set a function to check the Operation table..
// Websockets...
ws.on('ACCOUNT_UPDATED',()=>
ws.send({amount:X})
}
router.post('/operation',(req,res)=>{
//considering all checks and sanitazions and every security measure
const {accountId,newTransaction} = req.body;
Account.findById(accountId)
.then(({status,amount})=>status)
.then(status => {
if (status === 'LOCKED'){
return Operation.create(amount)
.then(created => res.json ({state: 'PENDING' ...});
}
return checkQueue();
});
哑巴
或者我可以等到所有任务都由LOCK完成(如果有的话)。(这是一种愚蠢的方法,因为它阻止了一切哈哈哈)
对不起,我懒于编写更多的伪代码...
每种方法都有其自身的含义和挑战。
您还可以使用RabitMQ,SQS,Redis(QUEUING)之类的解决方案一次执行一项操作,而这需要承担大部分Node职责。
总而言之,我的意思是:
但是通过了解主要问题是什么。希望我对解决方案有所了解。
好运:)
更多信息: https://thecodebarbarian.com/mutual-exclusion-patterns-with-node-promises