1、什么是幂等
接口幂等性是指用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。
幂等是指一个操作无论执行多少次,产生的效果是一样的。
幂等与是不是分布式高并发都没有关系,关键是所执行的操作是不是幂等的。
2、开发中的幂等场景
(1)页面上快速点击按钮重复提交表单、重复刷新页面,导致产生了多条重复的数据、放大了更新增量导致错误的结果。
(2)接口调用超时,通常会增加重试。第一次请求接口超时了,请求方没能及时获取返回结果(此时有可能已经成功了),为了避免返回错误的结果,于是会对该请求重试几次,这样也会产生重复的数据。
(3)消费者在消费消息时,有时候会消费重复的消息,也可能会产生重复的数据。
3、典型的幂等数据库操作
create table `order` (
`id` int unsigned not null auto_increment primary key,
`money` int not null default 0
)
(1)查询操作
查询一次与两次的结果是一样的
select * from order where id = 1
(2)删除操作
删除多次的结果是一样的,最终只会删除一次
delete order where id = 1
(3)定值更新操作
这样更新多次结果都是一样的
update order set money = 100 where id = 1
4、典型的非幂等数据库操作
(1)创建操作
多次执行造成插入重复的记录,典型场景如,创建用户、批量导入
insert into order (money) values (100)
(2)增量更新操作
多次执行增量更新将放大增量,典型场景如,加分/扣分、点赞
update order set money = money + 10 where id = 1
(3)根据其他条件更新
select status from order_status where order_id = 1 // if order_status = 1, then update
update order set money = 200 where id = 1
5、非幂等操作,实现幂等性
(1)创建操作
对创建操作,可以通过主键、唯一键或组合唯一键避免重复创建记录。重复不插入,或重复更新。以通过用户名创建用户为例,对用户名加唯一键。
alter table user add unique key index_user_username (`username`)
select * from user where username = 'xxx' //首先查询是否存在,存在则不插入
insert into order (username, age) values ('xxx', 20) //对用户名加唯一键,如果创建报错,则说明用户已创建,此时查询已创建的用户信息返回即可
对于不能创建唯一键的场景,可以通过分布式锁加时间限制,避免短时间内生成重复数据。
(2)增量更新
单纯的增量更新,并没有很好的方法防止幂等问题,需要增加额外的业务限制。
对于可以重复更新但短时间内不可以重复更新的业务,可以通过分布式锁加时间限制,如一定时间内不能重复更新。
setnx lock 1 1000
do...
del lock
对于只能增量更新一次的,可以记录状态,通过事务+悲观锁保证更新一次。如点赞,可以在用户表中增加是否点赞的状态标记。
start transaction
select supoort_status from user where id = 1 for update // 主键或唯一键作为条件,避免锁表
if status = 1; then
update support_count set count = count + 1 where id = 1 // 点赞次数增加
update user set support_count = 2 where id = 1
commit
对于只能增量更新一次的,也可以增加更新记录,通过唯一键保证唯一性。如点赞,可以增加一条点赞记录并增加唯一键
select * from support_log where user_id = 1 // 判断是否已有点赞记录
insert into support_log (user_id) values (1) // 将user_id设置为唯一键
(3)根据其他条件更新
事务+悲观锁
start transaction
select status from order_status where id = 1 for update // 主键或唯一键作为条件,避免锁表
if status = 1; then
update order set money = 200 where id = 1
update order_status set status = 2 where id = 1
commit
分布式高并发系统如何保证对外接口的幂等性?
幂等性总结



