【从零开始学习重要知识点 | 第一篇】快速了解什么是幂等性以及常见解决方案

前言:

当我们在设计和实现分布式系统时,幂等性 是一个非常重要的概念。幂等性可以简单地理解为:对于同一操作,不论执行多少次,产生的影响都是相同的。这个概念在分布式系统中非常重要,因为在这种环境下,由于网络延迟、消息重复等原因,可能会导致同一操作被执行多次。如果操作不具备幂等性,那么这些重复的操作可能会导致系统状态的不一致性、数据的错误或者其他问题。

因此,幂等性是分布式系统中必须要考虑的一个重要问题。在本文中,我们将深入探讨什么是幂等性,为什么它在分布式系统中如此重要,以及如何在设计和实现分布式系统时考虑幂等性。

目录

前言:

什么是幂等性?

常见产生幂等性问题的场景:

常见的幂等解决方案:

1.token机制:

2.分布式锁:

3.MySQL去重表:

总结:


什么是幂等性?

幂等性简单来讲:对于同一操作,不论执行多少次,产生的影响都是相同的。

换一种方式也可以描述为:

对于相同的输入,无论进行多少次重复操作,都应该保持其结果一致。

我们来举一个现实的例子:

当我们在用户网站进行注册的时候,当我们因为系统卡顿而多次点击注册按钮的时候,后端肯定不会在数据库生成多个一样的账号密码,而是只有一个账号密码

在这个场景中去解释幂等性:幂等性就是多次重复调用操作(因为卡顿多次点击注册),对结果只影响一次(最终只注册一个账号密码

比方说:支付接口没有做幂等性导致重复扣款问题订单接口没有做幂等性导致的订单重复生成问题

那么在这种情况下,重复订单的入库就是一个明显的bug。而在保证幂等性的情况下:

因此从后端来看:幂等性就是保证同一个接口在重复接收同一个请求的时候,需要保证效果的唯一性。

常见产生幂等性问题的场景:

  • 网络波动引起的重复请求
  • 使用了失效或者超时重试机制导致接口被重复调用
  • 消息队列中间件的默认重试机制
  • 页面重复刷新
  • 用户重复点击提交按钮
  • 使用浏览器后退按钮重复之前的操作,导致重复提交数据。

前端重复提交消息重复消费任务重复执行

常见的幂等解决方案:

1.token机制:

当用户发起请求之前,后端会生成一个键值对存储在redis中,键是当前请求用户的ip+参数,值是token。

当用户向后端发送请求的时候,需要携带token,我们在redis中判断是否存在token,如果存在就删除token并且执行操作,如果不存在token就说明当前已经有相同的请求被执行过。

我们还是用之前的订单接口来举例:

此时的token已经被删除,那么第二次:

我们通过携带token的方式,就保证了这种接口的幂等性。

token机制的缺陷:

  1. 复杂性和管理成本: 引入 Token 机制会增加系统的复杂性,包括生成、传输、校验和存储 Token 等环节,导致系统开发和维护的成本增加。

  2. 网络开销: 每次请求都需要携带 Token,并且服务端需要验证 Token 的有效性,这会增加网络开销和服务端的处理负担,降低系统的性能表现。

  3. 并发冲突: 在高并发场景下,可能会出现多个请求同时携带相同的 Token 并被同时处理的情况,导致操作重复执行或者数据不一致的问题。

  4. 安全性风险: 如果 Token 不够随机或唯一,可能会受到恶意攻击者的攻击,从而破坏系统的幂等性。此外,泄露 Token 也可能导致安全隐患。

  5. 存储压力: 如果大量 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 机制、请求参数校验、消息队列处理等,来确保接口的幂等性。在实际应用中,需要综合考虑系统需求、性能表现和安全要求,选择合适的幂等性解决方案。最终,通过有效地实现幂等性,我们能够构建更加稳健、可靠的系统,为用户提供更好的体验和保障数据的一致性。

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

相关推荐
XiaoLeisj24 分钟前
【JavaEE初阶 — 多线程】单例模式 & 指令重排序问题
java·开发语言·java-ee
dayouziei26 分钟前
java的类加载机制的学习
java·学习
励志成为嵌入式工程师1 小时前
c语言简单编程练习9
c语言·开发语言·算法·vim
捕鲸叉2 小时前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer2 小时前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq2 小时前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
记录成长java3 小时前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山3 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
睡觉谁叫~~~3 小时前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程3 小时前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust