跳到主要内容

如何打造高效幂等组件,确保数据一致性

首先,我们来介绍什么是幂等,幂等(Idempotent) 是一个数学和计算机科学中的概念,主要描述的是一种属性,即一个操作可以被多次应用,但结果仍然保持不变。在数学中,幂等通常用于描述某些运算或函数的特性。

例如,对于单目运算,如果一个运算对于在范围内的所有数,多次进行该运算所得的结果和进行一次该运算所得的结果相同,那么该运算就是幂等的。在双目运算中,如果当参与运算的两个值是等值的情况下,运算结果与参与运算的两个值相等,那么该运算也是幂等的

Web项目中的幂等性

在web项目中,幂等性同样是一个重要的概念。这主要是因为在网络和分布式系统中,由于网络的不稳定性和其他潜在问题,可能会导致请求被重复发送。如果一个操作不是幂等的,那么重复执行该操作可能会产生不一致的结果或副作用。

例如,一个非幂等的操作可能会导致数据被重复添加、更新或删除,从而破坏数据的一致性。

因此,JavaWeb项目需要保证幂等性,主要是为了确保无论请求被发送一次还是多次,系统都能产生相同的结果。这有助于避免由于重复请求导致的数据不一致或其他潜在问题。实现幂等性的方法有很多种,包括但不限于使用数据库唯一索引、乐观锁、分布式锁、令牌等技术

总的来说,幂等性是JavaWeb项目中一个非常重要的概念,它有助于确保系统的稳定性和数据的一致性。通过实现幂等性,我们可以有效地处理重复请求,并减少由于网络不稳定或其他原因导致的潜在问题

关于实现幂等的常见方法和技术:

  1. 唯一标识符(Unique Identifiers)
    为每个请求生成一个唯一的标识符(如UUID),并将其作为请求的一部分发送。当接收到请求时,服务器可以检查该标识符是否已处理过。如果已处理,则拒绝或忽略该请求;如果未处理,则处理该请求并记录标识符
  2. 数据库唯一约束
    使用数据库的唯一约束(如主键或唯一索引)来确保即使多次尝试插入相同的数据,也只有一条记录会被保存。如果尝试插入重复的数据,数据库会抛出异常,服务器可以捕获这个异常并返回幂等性的响应
  3. 乐观锁(Optimistic Locking)
    使用版本号或时间戳来检查数据是否已被其他操作修改过。在更新数据时,如果版本号或时间戳与预期的不符,则拒绝更新并返回冲突信息。这样,即使多次尝试更新相同的数据,也只有一次会成功
  4. 分布式锁(Distributed Locking)
    在分布式系统中,可以使用分布式锁来确保同一时间只有一个节点能够执行某个操作。这可以防止多个节点同时处理相同的请求,从而实现幂等性

而今天我们介绍的幂等性组件,不仅仅是单纯实现幂等,而是要在保证实现幂等的前提下,还要考虑高并发下的高效率执行,不能影响程序的性能和吞吐量

基于上述这些要求,最终选择利用redis来实现,而在对使用redis上,Redisson又是非常优秀的开源中间件,其中的分布式锁是非常的经典,项目中也对分布式锁做了封装,使用起来灵活而方便,而这次幂等组件也是对Redisson基础上进行封装,保证了性能,支持MQ中间件和用户请求的幂等。

为什么不直接使用分布式锁

可能小伙伴会有这样的疑惑,直接使用分布式锁不就行了,为什么还要额外设计出幂等组件?首先直接使用分布式锁是可以实现幂等的,当然业务逻辑验证也要做验证,但其实分布式锁会浪费一些性能

特点

分布式锁的特点是多个请求并发执行,这些请求是来自不同的用户,也就是这些请求虽然要依次等待锁执行,但最终还是要把这些请求都执行完的(执行时间太长超时的异常情况排除),总结起来就是都要获得锁,没有获得锁的请求,也要争取获得锁接着执行

幂等的特点也是多个请求并发执行,但这些请求是来自同一个用户,也就是说这些请求只要保证第一个请求能执行,其余的请求要直接拒绝掉,总结起来就是只有第一个请求获得锁执行就可以,其余的请求看到已经上了锁,那么就要直接结束掉

这个也是我在面试别人时,经常会问的问题,知道这个特点后,才真正能掌握为什么需要幂等。所以建议小伙伴认真学习此文章,下来我们就来详细的介绍幂等组件

dock-data-center-repeat-execute-limit-framework

使用

1 在Springboot配置redis地址

2 添加依赖

<dependency>
<groupId>org.javaup</groupId>
<artifactId>dock-data-center-repeat-execute-limit-framework</artifactId>
<version>${revision}</version>
</dependency>

3 指定方法

@RepeatExecuteLimit(name = CONSUMER_UP_DIMENSION_MESSAGE,keys = {"#upgradeDimensionMessage.messageId"})
public void doConsumer(UpgradeDimensionMessage upgradeDimensionMessage, Acknowledgment acknowledgment)

@RepeatExecuteLimit注解属性

属性值类型可否默认含义备注
nameStringY业务名如:consumerApiDataMessage
keysString[]N幂等唯一标识可指定多个,并支持SpEL表达式,如#apiData.id
durationTimelongY在多长时间内一直保持幂等,如果不配置则以执行方法为准默认0
messageStringY当消息执行已经出发防重复执行的限制时,提示信息默认 提交频繁,请稍后重试

以上就是幂等性组件的使用,可以看到使用起来非常的简单,只需添加依赖,在要保证幂等的方法上添加注解即可。

接下来详细的讲解幂等性组件的设计