计算机应用开发中的幂等(idempotent)是什么?

诸神缄默不语-个人CSDN博文目录

幂等(idempotent)是一个数学与计算机科学概念,它指的是一个操作、方法或函数在被多次执行时,其结果与执行一次相同,即多次执行不会产生额外的影响。这个概念在分布式系统、网络通信、API设计等领域非常重要,用于确保系统的稳定性和数据的一致性。

在这里插入图片描述

幂等的定义

  • 数学定义:在数学中,幂等元素是指被自己重复运算(或对于函数是为复合)的结果等于它自己的元素。例如,乘法下仅有两个幂等实数,为0和1。
    f ( x ) = f ( f ( x ) ) f(x)=f(f(x)) f(x)=f(f(x))
    如求绝对值 a b s ( x ) = a b s ( a b s ( x ) ) abs(x)=abs(abs(x)) abs(x)=abs(abs(x)) 就是幂等的
  • 计算机科学定义:在编程中,幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。
    这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
    一个接口,不管我调多少次,只要参数不变,结果也应该不变。

GET请求一般要求幂等。

幂等的重要性

幂等性在设计分布式系统、网络通信、API设计等方面具有非常重要的应用。例如,在交易支付系统中,下订单是一个常见的业务场景,如果不做幂等性设计,用户多次点击提交按钮可能会导致重复下单,从而造成资源浪费或数据不一致。

幂等的实现方式

幂等性判断

  • 使用防重Token令牌:在客户端发起请求之前,生成一个唯一的防重Token令牌,并将令牌携带在请求中。服务端在接收到请求后,校验令牌,如果令牌已经被使用过,则说明该请求是重复请求,直接返回已处理过的结果。在这里插入图片描述
  • 基于唯一键的幂等:通过为每个操作分配一个唯一的标识符(如订单ID、用户ID等),并在数据库中检查该标识符是否存在,来确保操作的唯一性。

通过理解幂等性的概念、重要性以及实现方式,我们可以更好地设计出稳定、可靠的系统,避免因重复操作导致的数据不一致等问题。

加锁

并发控制,先加锁,然后进行幂等性判断(可以基于状态机、流水表、唯一性索引等等进行重复操作的判断),最后进行数据的更新,将数据进行持久化。
在这里插入图片描述
建议使用Redis实现分布式锁,因为他是非阻塞的高效率的互斥锁。非常适合在幂等控制场景中。

数据库唯一性约束

数据库的唯一性约束都要加好,这是系统的最后一道防线。万一前面的锁失效了,这里也能控制得住不会产生脏数据。

使用数据库唯一主键完成幂等性:需要注意的是,该主键一般来说并不是使用数据库中自增主键,而是使用分布式 ID 充当主键,这样才能能保证在分布式环境下 ID 的全局唯一性。
在这里插入图片描述

版本号+乐观锁

本文撰写过程中参考的其他网络资料

  1. 幂等性是什么?幂等性方案详解(5大步骤原理)
  2. 啥是“幂等”?
  3. 解决幂等问题,只需要记住这个口诀!
  4. 什么是幂等性?
  5. 浅谈幂等
  6. 实现幂等性的 4 种常见方法
### 等性处理的概念 等(Idempotent)作为数学与计算机科学中的一个重要概念,在微服务架构的一致性方面扮演着不可或缺的角色[^1]。具体而言,一个等操作指的是无论该操作被执行多少次,对于系统的最终效果都等同于仅执行了一次的效果。 在分布式系统设计中,特别是在网络环境不稳定的情况下,客户端可能会因为超时等原因重复发送请求给服务器端。如果这些请求不是等性的,则可能导致数据不一致或者错误的结果;而通过确保某些关键接口具备等特性,可以有效减少此类问题的发生概率。 ### 接口等性和RESTful API 的等性 当提到接口的等性时,意味着即使同一个客户端发出多个相同的HTTP请求到同一资源上,也应该只产生预期的行为一次。例如PUT和DELETE方法通常被认为是等的,因为它们修改或删除指定位置的数据对象不会因调用次数增加而导致不同的结果[^2]。 ### 保证等性的作用 为了维护系统的稳定性和可靠性,保障等性具有重要意义: - **防止重复提交**:避免由于网络延迟或其他原因造成的用户无意间多次点击按钮从而引发不必要的业务逻辑; - **简化异常恢复机制**:在网络中断后重新发起未完成的操作变得更加容易管理而不必担心会破坏现有状态; - **提高用户体验**:减少了不确定因素带来的困扰,使得应用程序更加健壮可靠。 ### 实现等性的几种方案 #### 数据库唯一主键约束 利用数据库表结构内的自然键或是自定义字段设置成唯一的索引来阻止重复记录被插入。这种方式简单直接适用于那些能够找到合适候选键的情况下的场景。 ```sql CREATE TABLE orders ( order_id BIGINT PRIMARY KEY, user_id INT NOT NULL, product_name VARCHAR(255), UNIQUE (order_id, user_id) ); ``` #### 数据库乐观锁、MVCC 思想 采用版本号控制的方式来进行并发访问冲突检测。每次更新前先读取当前最新版本的信息并将其一同写回数据库中去验证是否有其他事务抢先进行了更改。多版本并发控制(MVCC)则允许不同时间点上的视图共存以便更好地支持高并发查询需求。 ```java public void updateOrderStatus(Long orderId, Integer expectedVersion){ String sql = "UPDATE orders SET status='PROCESSED', version=version+1 WHERE id=? AND version=?"; int affectedRows = jdbcTemplate.update(sql, orderId, expectedVersion); if (affectedRows == 0) { throw new OptimisticLockingFailureException("Update failed due to concurrent modification."); } } ``` #### 防重Token令牌 + Redis缓存 生成一次性使用的随机字符串作为token存储于Redis这样的内存级高速缓存组件里,并关联具体的业务动作。每当接收到新的API请求时就检查是否存在对应的token值存在即可判断是否已经处理过此请求。 ```python import redis from uuid import uuid4 r = redis.Redis() def process_payment(order_id): token_key = f'payment:{order_id}' with r.pipeline() as pipe: while True: try: # Start transactional block pipe.watch(token_key) existing_token = pipe.get(token_key).decode('utf-8') if pipe.exists(token_key) else None if not existing_token: unique_token = str(uuid4()) pipe.multi() pipe.setex(name=token_key,value=unique_token,time=3600)# Set expiration time for the key result = pipe.execute()[0] return {"status": "success", "message":f"Payment processed successfully with token {result}"} raise Exception(f"Duplicate request detected via token: {existing_token}") except redis.WatchError: continue process_payment(1234567890L) ``` #### 下游传递唯一序列号 让上游服务负责分配全局唯一的ID给每一个需要等保护的任务实例化过程,然后在整个链路传播过程中保持不变直到最后一步确认结束为止。这样做的好处是可以跨越多个独立部署单元之间追踪整个流程的状态变化情况。 ### 利用状态机实现等性校验 许多实际应用中的实体往往伴随着生命周期的不同阶段转换而来,比如订单从创建到支付再到发货等一系列环节构成了完整的交易周期。因此可以通过构建有限自动机模型来描述各个可能发生的事件及其触发条件,进而达到限制非法转移路径的目的,间接实现了等功能[^3]。 ### 引入等性后的潜在影响 引入等性虽然有助于增强系统的鲁棒性和一致性水平,但也带来了额外的设计复杂度以及性能开销等问题。开发人员需权衡利弊做出合理的选择以满足特定应用场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

诸神缄默不语

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值