前言:
当我们在设计和实现分布式系统时,幂等性是一个非常重要的概念。幂等性可以简单地理解为:对于同一操作,不论执行多少次,产生的影响都是相同的。这个概念在分布式系统中非常重要,因为在这种环境下,由于网络延迟、消息重复等原因,可能会导致同一操作被执行多次。如果操作不具备幂等性,那么这些重复的操作可能会导致系统状态的不一致性、数据的错误或者其他问题。
因此,幂等性是分布式系统中必须要考虑的一个重要问题。在本文中,我们将深入探讨什么是幂等性,为什么它在分布式系统中如此重要,以及如何在设计和实现分布式系统时考虑幂等性。
目录
前言:
什么是幂等性?
常见产生幂等性问题的场景:
常见的幂等解决方案:
1.token机制:
2.分布式锁:
3.MySQL去重表:
总结:
什么是幂等性?
幂等性简单来讲:对于同一操作,不论执行多少次,产生的影响都是相同的。
换一种方式也可以描述为:
对于相同的输入,无论进行多少次重复操作,都应该保持其结果一致。
我们来举一个现实的例子:
当我们在用户网站进行注册的时候,当我们因为系统卡顿而多次点击注册按钮的时候,后端肯定不会在数据库生成多个一样的账号密码,而是只有一个账号密码
在这个场景中去解释幂等性:幂等性就是多次重复调用操作(因为卡顿多次点击注册),对结果只影响一次(最终只注册一个账号密码)
比方说:支付接口没有做幂等性导致重复扣款问题。订单接口没有做幂等性导致的订单重复生成问题。
那么在这种情况下,重复订单的入库就是一个明显的bug。而在保证幂等性的情况下:
因此从后端来看:幂等性就是保证同一个接口在重复接收同一个请求的时候,需要保证效果的唯一性。
常见产生幂等性问题的场景:
- 网络波动引起的重复请求
- 使用了失效或者超时重试机制导致接口被重复调用
- 消息队列中间件的默认重试机制
- 页面重复刷新
- 用户重复点击提交按钮
- 使用浏览器后退按钮重复之前的操作,导致重复提交数据。
前端重复提交,消息重复消费,任务重复执行
常见的幂等解决方案:
1.token机制:
当用户发起请求之前,后端会生成一个键值对存储在redis中,键是当前请求用户的ip+参数,值是token。
当用户向后端发送请求的时候,需要携带token,我们在redis中判断是否存在token,如果存在就删除token并且执行操作,如果不存在token就说明当前已经有相同的请求被执行过。
我们还是用之前的订单接口来举例:
此时的token已经被删除,那么第二次:
我们通过携带token的方式,就保证了这种接口的幂等性。
token机制的缺陷:
-
复杂性和管理成本: 引入 Token 机制会增加系统的复杂性,包括生成、传输、校验和存储 Token 等环节,导致系统开发和维护的成本增加。
-
网络开销: 每次请求都需要携带 Token,并且服务端需要验证 Token 的有效性,这会增加网络开销和服务端的处理负担,降低系统的性能表现。
-
并发冲突: 在高并发场景下,可能会出现多个请求同时携带相同的 Token 并被同时处理的情况,导致操作重复执行或者数据不一致的问题。
-
安全性风险: 如果 Token 不够随机或唯一,可能会受到恶意攻击者的攻击,从而破坏系统的幂等性。此外,泄露 Token 也可能导致安全隐患。
-
存储压力: 如果大量 Token 需要被管理和存储,可能会给系统的存储带来一定的压力,尤其是在高并发场景下。
2.分布式锁:
其实就是基于redis去构造一个分布式锁。具体的构造方法的话,这里就不多介绍了,下面是我之前一篇文章的链接,详细的介绍了如何基于redis构造分布式锁。
【从零开始学习Redis | 第六篇】爆改Setnx实现分布式锁-CSDN博客https://liyuanxin.blog.csdn.net/article/details/134677169那么通过分布式锁来保证幂等性的逻辑也很简单:
我们把传入的参数和用户id作为键值对来构造出一个键值对。每一次进来都要尝试构造键值对,如果构造成功,就执行业务逻辑代码,如果没有执行成功,就拒绝这次请求
第一次构造成功:
第二次构造失败:
其实就算使用redis中普通的set也是可以的,因为这个本质就是在利用redis中set创建k-v的唯一性。
之所以要用setnx,是要保证redis中不会因为构造分布式锁而留下大量的键值对,使用setnx在限定时间后,键值对就会过期被删除。
需要注意的是:我们这种简单的基于setnx构造的锁,会出现锁误删的问题,在我上面贴出来的文章中也详细介绍了锁误删的情况,大家如果想尝试用Redis来构造分布式锁的话,可以看一看。
这里提到了锁,很多朋友也会关联的想到synchronized,但是synchronized做的是代码块的同步,他会锁住代码块,导致程序并发性能的大大降低。关于这些点我在我上面贴的那篇文章里面也有讲。在这里再贴一下:
【从零开始学习Redis | 第六篇】爆改Setnx实现分布式锁-CSDN博客https://liyuanxin.blog.csdn.net/article/details/134677169
3.MySQL去重表:
就是在存入MySQL之前,先要检查一下是否有相同数据,如果有相同数据就拒绝插入。
总结:
总之,幂等性在分布式系统和接口设计中扮演着至关重要的角色。通过确保相同操作的重复执行不会产生额外的影响,幂等性能够提升系统的可靠性、稳定性和安全性。然而,实现幂等性并非易事,面临诸多挑战,包括并发冲突、性能开销、安全风险等问题。针对这些挑战,我们可以采取一系列策略和技术手段,例如使用 Token 机制、请求参数校验、消息队列处理等,来确保接口的幂等性。在实际应用中,需要综合考虑系统需求、性能表现和安全要求,选择合适的幂等性解决方案。最终,通过有效地实现幂等性,我们能够构建更加稳健、可靠的系统,为用户提供更好的体验和保障数据的一致性。
如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!