分布式系统如何防止重复下单?

举报
赵KK日常技术记录 发表于 2023/06/09 10:18:08 2023/06/09
【摘要】 问题背景:在高并发的分布式系统中,同一用户的多个请求可能会在短时间内到达不同的服务节点,并触发重复的下单操作,这会导致资源浪费和数据一致性问题。​![请在此添加图片描述](https://developer.qcloudimg.com/http-save/yehe-admin/463b7232dc64a568d7ae40718d084b23.png?qc_blockWidth=768&qc_...
问题背景:在高并发的分布式系统中,同一用户的多个请求可能会在短时间内到达不同的服务节点,并触发重复的下单操作,这会导致资源浪费和数据一致性问题。


![请在此添加图片描述](https://developer.qcloudimg.com/http-save/yehe-admin/463b7232dc64a568d7ae40718d084b23.png?qc_blockWidth=768&qc_blockHeight=354)


如何避免重复下单:

1. 使用唯一ID:每个订单生成一个唯一ID,下单请求中包含这个ID。服务端校验ID的唯一性来拒绝重复请求。可以使用UUID,数据库主键等作为ID。

2. 悲观锁:在处理下单请求时,对订单数据行锁定。其他节点的重复请求会被阻塞,直到锁被释放。这种方式要考虑锁的性能影响。

3. 乐观锁:使用订单版本号。请求中包含版本号,处理请求前校验当前版本号与数据库匹配,如果版本不一致则拒绝请求。这需要考虑版本号更新的原子性。解决ABA问题:乐观锁机制存在ABA问题,即一个值从A变B,再变回A,这时候版本号没变,但数据实际已变化。解决方案是使用时间戳版本号,每个更新记录时间戳,版本号为时间戳。即使值变为A,时间戳也已改变,可以避免ABA问题。示例代码:
下单请求:

```javascript
public class OrderRequest {
    private String orderId; //唯一ID
    private long version;   //时间戳版本号
}
```

订单表:

```javascript
public class Order {
    private String orderId; 
    private long version;     //时间戳版本号
    //其他字段...
}
```

处理请求:

```javascript
public void placeOrder(OrderRequest request) {
    Order order = orderDao.getById(request.getOrderId());
    if (order == null) {   //新订单
        saveNewOrder(request); 
    } else {               //已存在订单
        if (order.getVersion() != request.getVersion()) {   //版本不一致,重复请求
            throw new DuplicateOrderException();
        } 
        //版本一致,正常保存订单,更新版本号
    } 
}
```

总结:分布式系统中防止重复下单是一个需要解决的难点。使用唯一ID,悲观锁和乐观锁(如时间戳版本号)等手段可以在一定程度解决这个问题。但还需要考虑这些方法带来的性能影响以及在高并发场景下的限制。综合使用多种手段可以达到较佳的效果

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。