携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情
前言
之前在文章分布式事务-消息队列实现分布式事务中有提到幂等性的问题,有好心的倔友提问到说如何支持/实现幂等性,刚好出篇文章说说幂等性。
在消息发送及接收过程中,如果出现失败的情况,发送方会执行重试,接收方也会重试,在重试过程中就可能会出现重复消费消息或者重复产生消息的情况。要避免重复消费消息对系统带来的影响,实现幂等性就是一个很重要的问题。
什么是幂等性
幂等性本来是数学的概念,用公式说明: f(f(x)) = f(x)
公式也直接说明了幂等性的特点:一个相同参数的操作,任意执行多次,与只执行一次的结果是一样的。
举例: 设置对象的属性为某个值,例如设置张三的年龄为10岁,这个操作无论设置多少次,张三的年龄始终是10岁,这说明此操作具备幂等性。
小明在银行存入100元,对应的操作是小明的账户余额+100元,这个实际场景只发生了一次,而系统操作如果执行了多次,则会造成与只执行一次不同的影响。
唯一约束实现幂等性
根据实际业务来确定唯一约束,然后在消费消息前,利用唯一约束来确定当前消息是否已经消费过。 例如: 账户A往账户B转账100元,系统首先会创建此次操作对应的订单号,然后消费者会待消费两条消息:
- 账户A-100元
- 账户B+100元
在每次消费消息前,对业务主键先进行保存校验,如果已经存在,保存校验不会通过,此时表示已经消费过。如果保存校验通过,则说明不存在重复消息,对其进行消费(进行业务动作)。
最简单的实现方法可以利用数据库的唯一索引,例如以上例子就可以设置订单号+账户id作为唯一索引,每次消费操作前都保存数据,订单号+账户id相同的数据不会保存成功;其他也有很多可以实现此方案的思路,例如Redis,利用setnx的命令特性。