今天的主题:接口幂等性的解决方案。原本是想把对象的存储过程和内存布局肝出来的,可是临时产生了变化,哈哈,这部份内容咱们留在下一期吧,有句话说的好,好事多磨,对吧。mysql
在实际项目开发中接口是咱们在开发中常常接触到的,并且是常常常常要写,每个项目可能都会伴随着大量的接口开发,在moon来涂鸦的这几个月,基本上就是在与接口做斗争了,新需求除了业务相关就是设计表和接口编写了。web
固然,在接口设计中咱们要考虑不少问题,安全性,格式,设计等等,今天咱们先来聊聊,在高并发环境下,接口幂等性的解决方案有哪些。redis
就是说在屡次相同的操做下保证最终的结果是一致的。sql
其实这个概念仍是比较简单的,很容易理解,那咱们思考一个问题,若是不保证接口幂等性会有什么问题?数据库
咱们简单的举个例子,如今有一个接口,提供了转帐的功能,a要给b转帐1000元,正常状况下咱们接口一次性就调用成功了,可是却由于网络抖动等其它缘由没有成功,因而就开始不停的重试,忽然网络好了,可是这时却连续发出去了三个请求,可是这个接口没有保证幂等性,因而从结果上来看就是a给b转了3000元,这显然是程序业务逻辑上不能接受的(其实moon能够当b的)。安全
token机制实际上是比较简单的,咱们先来简单的说一下流程。网络
图示以下:并发
token机制实现方式仍是比较简单的,可是其实对于咱们某些响应速度要求很高的业务不太友好,缺点就是须要多一次请求获取token的过程。jvm
正常来讲是每次请都会生成一个新的token,若是有极限状况下,有两个请求都带着相同的token进来,会存在都走入判断是否存在的过程,可能都会同时查到存在,这样也会有问题,针对这种状况,咱们能够在删除前判断下是否存在,存在就删除,为了保证原子性,这部分逻辑建议使用lua脚本完成。svg
去重表的机制是根据mysql惟一索引的特性来的,咱们先来讲下它的流程:
图示以下:
去重表机制的问题有两点:
过程以下:
这里咱们是利用了redis setnx 的特性来完成的。
setnx:只在键key不存在的状况下,将键key的值设置为value。若键key已经存在,则SETNX命令不作任何动做。命令在设置成功时返回1,设置失败时返回0。
图示以下:
这种方案能够说是针对上一个方案改进的,效率也会提升不少。
这种机制适用于有不一样状态的业务,moon的上一家公司就是这样作的。
咱们的订单系统,一条订单会有多个状态,如:待付款,锁定,已付款等状态,而这些状态都是有流程和逻辑的,咱们能够根据这个状态判断是否执行后续业务操做。
就是数据库中增长版本号字段,每次更新根据版本号来判断
过程以下:
这个图示我就再也不画了,仍是比较简单的
假设每一次拿数据,都有认为会被修改,因此给数据库的行上锁,也是基于数据库特性来完成。
当数据库执行select for update时会获取被select中的数据行的行锁,所以其余并发执行的select for update若是试图选中同一行则会发生排斥(须要等待行锁被释放),所以达到锁的效果。
START TRANSACTION; # 开启事务 SELETE * FROM TABLE WHERE .. FOR UPDATE; UPDATE TABLE SET ... WHERE ..; COMMIT; # 提交事务
关于接口幂等性这部份内容,解决方案其实大同小异,不少方式的原理都是同样的,更多的其实都是在业务链路中去过滤,也会有不少是有消息中间件去解决的,默认在中间件这一层就直接过滤掉了,固然每种方式都有各自的优势和缺点,须要结合当前的业务去选择,今天的文章内容,你get到了吗?
我是moon,下一篇,真的要讲jvm了~ 下次见~