幂等
带着以下3个问题来讨论幂等
- 什么是幂等
- 什么时候需要幂等
- 怎么实现幂等
1. 什么是幂等
- google Idempotence 得到以下结果 :
Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application. - 百度里搜到的一般都是这段的简单的中文翻译. 我理解的幂等, 一般是用在对外暴露的接口上, 目的是为了防止重复调用造成数据错误处理.
- 幂等其实我记得最早应该是网络协议中用到的, 网络协议中发送报文时, 网络中经常需要面临的问题就是网络超时, 而超时的常见处理策略就是重发. 如果客户端往服务端发送报文超时了, 可能发送超时, 服务端没有收到, 也可能服务端收到了但响应超时, 只要服务端是幂等的, 客户端的重复请求服务方会回应是重复报文, 客户端就知道已经发送成功了. 这样就保证了网络的可靠性设计.
2. 什么时候需要幂等
幂等是为了保护数据不被重复错误处理.
- 正常数据操作就只有增删改查, 查询操作总是幂等的, 所以严格来说其他三种操作都要考虑幂等性, 特别是在一些关键业务数据, 比如账户/金额/订单交易等等.
- 对外暴露的接口, 不管是rpc还是http或者是消费上游发过来的消息,都有可能会有重复的可能. 这时候服务暴露方或者消息消费方都必须设计为幂等的.
- http: 用户重复提交页面请求, 或者客户端服务器超时重发http请求
- rpc : 比如我们常用的dubbo框架, 接口超时或失败默认会进行重试 (当然可以设置不重试)
- mq消息 : 很多mq消息为了保证可靠性, 如果消息发送端发送超时, 会尝试重新发送消息.
3. 怎么实现幂等
以下几种常见的也是开发中常用的方案, 其实是在整个服务执行过程的多个不同阶段去保证幂等性的, 其实我认为方案很多, 只要在破坏数据之前校验都可以的.
-
- 用户页面提交请求的时候, 就先进行重复提交的校验. 常用的方案是采用唯一token生成器, 用户加载页面的时候, 会分配一个唯一token, 用户提交的时候会带着这个token, 我们校验同一个token是否重复提交了.
-
- 去重表方案, 个人感觉这个方案还是比较实用的, 而且去重表可以设置为分库分表的, 可以扩展性能. 去重表就是在操作之前,先插入一条记录, 利用唯一索引防止重复操作, 如果记录已存在, 接口可以直接返回已处理, 不要重复操作, 或者直接返回成功. 与之类似的方案就是利用缓存比如redis来判断重复.
-
- CAS方案, 可以是要求请求中必须带有版本号, 利用版本号来CAS更新数据.
-
- 利用数据库的一致性, 比如mysql的insert ignore操作和insert on duplicate update等sql, 也能做到保证数据的一致性.
这些都是我自己常用的, 在这里简单总结一下.