node 如何和处理同一用户并发的两个一模一样的请求?

发布于 2022-09-05 20:56:22 字数 968 浏览 28 评论 0

最近碰到个问题,就是同一个用户几乎同时的发起两次同样的请求,比如买一样东西有一定几率会出现购买两次的情况,代码逻辑判断没错,问题出在判断时序上面。下面是一段购买商品的逻辑判断:

'buyItem': async (req, res, next) => {
  const itemId = req.params.itemId;
  const userId = req.headers['current-user-id'];

  const orderRecord = await Order.find(itemId, userId)//do mongodb search
  if (orderRecord && orderRecord.status === 'paid') {//第二次请求对于这个是否购买过的判断的结果是未购买,因为第一个请求还未创建订单。
    return res.status(400).json({
      'code': 101,
      'message': 'you have already bought it',
      'result': {}
    })
  }
  // 第一次请求执行到这里了
  const orderNew = await Order.create(itemId, userId)//do mongodb create
  await User.deduct(userId, item.price);

}

两次几乎同时的请求,但有一定的先后顺序,第一个请求执行到即将创建订单,但第二个请求因为第一个请求还未创建,导致判断上不符合预期。

我现在的想法是:

方法一:把创建订单放到最前面,因为 mongodb 有读写 latch,所以判断订单是否存在来决定是否进行后续操作,这样虽然能解决比较关键的路由,但并不普适。

方法二:对访问频率进行限制(rate-limit),但因为我使用了 cluster,不好做。

后端采用:node express
不知道各位大神有没有相似情况的解决方案.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

秋千易 2022-09-12 20:56:22

加载页面的时候生成一个token,提交订单的时候一起提交,服务端接受后进行校验!
如果服务端已经处理了该token,那么抛弃当前请求;否则就处理请求

轻许诺言 2022-09-12 20:56:22

最近做了个限时抢购的功能,也遇到了同样的问题,由于并发导致的资源竞争问题,也就是“狼多肉少”,处理的思路,对肉做限制,还是对狼制定规则,一个一个来。技术上就是 1.对数据资源做限制 2.制定访问的规则,先到先到,依次处理,数据库层面:利用数据库锁的机制,限制其它没它请求 代码层面:处理思路也很多吧,目前就想到了三种方案,第一:前端做限制 第二:利用队列,将并发问题转化为串行执行, 第三:实现锁的机制,将资源和任务加锁,任务结束,解锁,利用redis可以实现一个锁的机制。方案选择要看并发量和具体的业务场景,目前还没具体的实现代码,只简单的描述了下,自己的一点思路和看法

浮生面具三千个 2022-09-12 20:56:22

是否可以在前端做判断呢,比如说,一个请求发出时,还未响应,这段时间,按钮无法再次点击.当然,这只适合正常流程,秒杀活动什么的不适合

白色秋天 2022-09-12 20:56:22

这个需要去重处理的,防止订单重复不仅需要前端进行控制,后端也要控制(有时候前端会有非法操作),后端处理:当一个订单来的时候,需要把未处理的订单的信息保存起来的中,(这里可以保存在一个全局变量中,推荐保存在数据库中:比如 redis中 ),根据用户的ID 进行标别,当下一个相同用户在来订单时候,查询是否未处理的订单 和 比较两个订单的时间间隔(这里可以自定义时间间隔进行去重合并)。当处理完订单后,在根据需求处理上一步保存的未处理的订单信息。

暮年慕年 2022-09-12 20:56:22
  1. 可以把请求加入队列,保证先后顺序,然后在一个一个对队列的请求做处理,并行变串行。

  2. 加锁

花间憩 2022-09-12 20:56:22

并发小的话可以加悲观锁试试

傲性难收 2022-09-12 20:56:22

@豆腐居士 的答案只适合对单用户的请求做排重,要想保证多客户端高并发下的资源(商品)状态维护,还需要服务端服务在处理时加锁,如果是分布式服务还需要redis或zookeeper来实现分布式锁。客户端请求的排重和商品防止二次购买是两个方面的问题。

望笑 2022-09-12 20:56:22

之前遇到过类似的问题,我是通过加锁来处理的

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文