防止订单重复提交或支付分布式锁方案设计

本文涉及的产品
应用实时监控服务-应用监控,每月50GB免费额度
可观测可视化 Grafana 版,10个用户账号 1个月
性能测试 PTS,5000VUM额度
简介: 防止订单重复提交或支付分布式锁方案设计

防止订单重复提交或支付分布式锁方案设计

在现代电子商务应用程序中,订单的提交和支付是核心业务流程之一。然而,由于各种原因,用户可能会多次提交订单或重复支付,这可能导致严重的问题,如库存错误、多次扣款等。为了解决这个问题,我们可以使用分布式锁来确保订单的唯一性,本文将介绍如何设计和实现一个防止订单重复提交或支付的分布式锁方案。

引言

在分布式系统中,多个节点同时访问共享资源时,需要一种机制来确保数据的一致性和唯一性。分布式锁就是这样一种机制,它可以用来协调不同节点对共享资源的访问,以防止并发冲突。在订单提交和支付的情景下,我们需要确保同一订单不会被多次提交或支付,因此需要一个分布式锁来保护订单数据。

分布式锁的选择

在设计分布式锁方案之前,我们需要选择合适的分布式锁实现。有多种分布式锁的实现方式,包括基于数据库、基于缓存、基于ZooKeeper等。在本文中,我们将使用基于缓存的分布式锁,因为它具有高性能和低延迟的特点,适用于订单提交和支付的场景。

我们将使用Redis作为缓存存储,因为Redis是一个高性能的内存数据库,具有分布式特性,可以方便地实现分布式锁。

设计分布式锁方案

步骤1:订单生成时获取锁

当用户提交订单时,系统首先需要生成一个唯一的订单号,并尝试获取一个分布式锁来锁定这个订单号。如果成功获取锁,说明订单号没有被使用过,可以继续创建订单;如果未能获取锁,说明订单号已经被其他用户占用,需要提示用户重新提交订单。

下面是获取锁的代码示例:

import redis

# 连接到Redis服务器
redis_client = redis.Redis(host='localhost', port=6379, db=0)

# 订单号
order_number = generate_order_number()

# 尝试获取锁
lock_key = f'order_lock:{order_number}'
lock_value = str(time.time())  # 使用当前时间作为锁的值
lock_acquired = redis_client.set(lock_key, lock_value, nx=True, ex=60)  # 设置锁的过期时间为60秒

if lock_acquired:
    # 获取锁成功,继续创建订单
    create_order(order_number)
else:
    # 获取锁失败,提示用户重新提交订单
    return "订单已经在处理中,请不要重复提交。"

在上面的代码中,我们首先生成一个唯一的订单号,然后尝试获取一个名为order_lock:{order_number}的锁,锁的值为当前时间戳,锁的过期时间设置为60秒。如果成功获取锁,就可以继续创建订单;如果获取失败,就返回一个提示消息给用户。

步骤2:订单支付时获取锁

当用户支付订单时,系统需要再次获取分布式锁来确保订单的唯一性。与订单生成时的逻辑类似,我们使用订单号作为锁的键,并尝试获取锁。如果成功获取锁,说明可以继续支付订单;如果获取失败,说明订单正在被其他用户支付,需要提示用户等待或重新支付。

下面是支付时获取锁的代码示例:

# 订单号
order_number = get_order_number_from_request()

# 尝试获取锁
lock_key = f'order_lock:{order_number}'
lock_value = str(time.time())  # 使用当前时间作为锁的值
lock_acquired = redis_client.set(lock_key, lock_value, nx=True, ex=60)  # 设置锁的过期时间为60秒

if lock_acquired:
    # 获取锁成功,继续支付订单
    process_payment(order_number)
else:
    # 获取锁失败,提示用户等待或重新支付
    return "订单正在支付中,请稍后或重新支付。"

同样,我们使用订单号作为锁的键,尝试获取锁,如果成功获取锁,就可以继续支付订单;如果获取失败,就返回一个提示消息给用户。

步骤3:释放锁

在订单生成或支付完成后,需要释放锁,以便其他用户可以使用相同的订单号进行操作。释放锁的代码如下:

# 订单号
order_number = get_order_number_from_request()

# 释放锁
lock_key = f'order_lock:{order_number}'
current_lock_value = redis_client.get(lock_key)

if current_lock_value and current_lock_value == lock_value:
    # 当前锁的值与之前设置的值相同,说明是当前用户的锁,可以释放
    redis_client.delete(lock_key)

在释放锁时,我们首先获取当前锁的值,并与之前设置的值进行比较,如果相同,说明是当前用户的锁,可以释放。

总结

通过使用基于Redis的分布式锁,我们可以有效地防止订单重复提交或支付的问题。在订单生成和支付时,通过获取和释放锁,可以确保同一订单只能被一个用户操作,从而保障了订单数据的一致性和唯一性。

在实际应用中,我们需要考虑更多的细节,如错误处理、超时处理等,以确保系统的稳定性和可靠性。同时,还可以考虑使用分布式事务来进一步增强数据一致性。

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
9月前
|
存储 NoSQL Java
分布式锁中的王者方案 - Redission
分布式锁中的王者方案 - Redission
101 1
|
2月前
|
消息中间件 架构师 数据库
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
45岁资深架构师尼恩分享了一篇关于分布式事务的文章,详细解析了如何在10Wqps高并发场景下实现分布式事务。文章从传统单体架构到微服务架构下分布式事务的需求背景出发,介绍了Seata这一开源分布式事务解决方案及其AT和TCC两种模式。随后,文章深入探讨了经典ebay本地消息表方案,以及如何使用RocketMQ消息队列替代数据库表来提高性能和可靠性。尼恩还分享了如何结合延迟消息进行事务数据的定时对账,确保最终一致性。最后,尼恩强调了高端面试中需要准备“高大上”的答案,并提供了多个技术领域的深度学习资料,帮助读者提升技术水平,顺利通过面试。
本地消息表事务:10Wqps 高并发分布式事务的 终极方案,大厂架构师的 必备方案
|
2月前
|
消息中间件 SQL 中间件
大厂都在用的分布式事务方案,Seata+RocketMQ带你打破10万QPS瓶颈
分布式事务涉及跨多个数据库或服务的操作,确保数据一致性。本地事务通过数据库直接支持ACID特性,而分布式事务则需解决跨服务协调难、高并发压力及性能与一致性权衡等问题。常见的解决方案包括两阶段提交(2PC)、Seata提供的AT和TCC模式、以及基于消息队列的最终一致性方案。这些方法各有优劣,适用于不同业务场景,选择合适的方案需综合考虑业务需求、系统规模和技术团队能力。
360 7
|
2月前
|
缓存 NoSQL Java
Spring Boot中的分布式缓存方案
Spring Boot提供了简便的方式来集成和使用分布式缓存。通过Redis和Memcached等缓存方案,可以显著提升应用的性能和扩展性。合理配置和优化缓存策略,可以有效避免常见的缓存问题,保证系统的稳定性和高效运行。
75 3
|
3月前
|
NoSQL 安全 PHP
hyperf-wise-locksmith,一个高效的PHP分布式锁方案
`hyperf-wise-locksmith` 是 Hyperf 框架下的互斥锁库,支持文件锁、分布式锁、红锁及协程锁,有效防止分布式环境下的竞争条件。本文介绍了其安装、特性和应用场景,如在线支付系统的余额扣减,确保操作的原子性。
48 4
|
3月前
|
NoSQL 算法 关系型数据库
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
本文详解分布式全局唯一ID及其5种实现方案,关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式 ID 详解 ( 5大分布式 ID 生成方案 )
|
8月前
|
消息中间件 数据挖掘 程序员
【建议收藏】高并发下的分布式事务:如何选择最优方案?
本文介绍了分布式事务的三种常见解决方案。在分布式系统中,事务处理变得复杂,需确保ACID特性。TCC(Try-Confirm-Cancel)方案适用于严格资金要求的场景,如银行转账,通过预留、确认和取消步骤确保一致性。可靠消息最终一致性方案适合一致性要求较低的场景,如电商积分处理,通过消息中间件实现最终一致性。最大努力通知方案则用于允许不一致的场景,如数据分析,通过重复通知尽可能达成一致性。选择合适的方案取决于具体应用场景。
238 5
|
4月前
|
存储 缓存 NoSQL
分布式架构下 Session 共享的方案
【10月更文挑战第15天】在实际应用中,需要根据具体的业务需求、系统架构和性能要求等因素,选择合适的 Session 共享方案。同时,还需要不断地进行优化和调整,以确保系统的稳定性和可靠性。
|
4月前
|
SQL NoSQL 安全
分布式环境的分布式锁 - Redlock方案
【10月更文挑战第2天】Redlock方案是一种分布式锁实现,通过在多个独立的Redis实例上加锁来提高容错性和可靠性。客户端需从大多数节点成功加锁且总耗时小于锁的过期时间,才能视为加锁成功。然而,该方案受到分布式专家Martin的质疑,指出其在特定异常情况下(如网络延迟、进程暂停、时钟偏移)可能导致锁失效,影响系统的正确性。Martin建议采用fencing token方案,以确保分布式锁的正确性和安全性。
78 0
|
6月前
|
存储 NoSQL Java
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)
这篇文章是关于Java面试中的分布式架构问题的笔记,包括分布式架构下的Session共享方案、RPC和RMI的理解、分布式ID生成方案、分布式锁解决方案以及分布式事务解决方案。
一天五道Java面试题----第十一天(分布式架构下,Session共享有什么方案--------->分布式事务解决方案)