如何实现幂等性

115 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情

前言

之前在文章分布式事务-消息队列实现分布式事务中有提到幂等性的问题,有好心的倔友提问到说如何支持/实现幂等性,刚好出篇文章说说幂等性。

在消息发送及接收过程中,如果出现失败的情况,发送方会执行重试,接收方也会重试,在重试过程中就可能会出现重复消费消息或者重复产生消息的情况。要避免重复消费消息对系统带来的影响,实现幂等性就是一个很重要的问题。

什么是幂等性

幂等性本来是数学的概念,用公式说明: f(f(x)) = f(x)

公式也直接说明了幂等性的特点:一个相同参数的操作,任意执行多次,与只执行一次的结果是一样的。

举例: 设置对象的属性为某个值,例如设置张三的年龄为10岁,这个操作无论设置多少次,张三的年龄始终是10岁,这说明此操作具备幂等性。

小明在银行存入100元,对应的操作是小明的账户余额+100元,这个实际场景只发生了一次,而系统操作如果执行了多次,则会造成与只执行一次不同的影响。

唯一约束实现幂等性

根据实际业务来确定唯一约束,然后在消费消息前,利用唯一约束来确定当前消息是否已经消费过。 例如: 账户A往账户B转账100元,系统首先会创建此次操作对应的订单号,然后消费者会待消费两条消息:

  1. 账户A-100元
  2. 账户B+100元

在每次消费消息前,对业务主键先进行保存校验,如果已经存在,保存校验不会通过,此时表示已经消费过。如果保存校验通过,则说明不存在重复消息,对其进行消费(进行业务动作)。

最简单的实现方法可以利用数据库的唯一索引,例如以上例子就可以设置订单号+账户id作为唯一索引,每次消费操作前都保存数据,订单号+账户id相同的数据不会保存成功;其他也有很多可以实现此方案的思路,例如Redis,利用setnx的命令特性。