幂等的这几个问题没有考虑到,你恐怕是在写Bug吧!

免费视频福利推荐:

2T免费学习视频,内含精选高频面试题、SSM、Spring全家桶、微服务、MySQL、MyCat、集群、分布式、高并发、中间件、Linux、网络、多线程,Jenkins、Nexus、Docker、ELK等等免费学习视频,持续更新!


往期热门文章推荐:

1、《2019年精选优秀博文都在这里了!》

2、格式化时间用了YYYY-MM-dd,元旦当天老板喊我回去改Bug!

3、39 个奇葩代码注释,看完笑哭了。。。

4、牛逼的人,都已经开始用文言文写代码了!

5、如何优雅地根治null值引起的Bug!


关于幂等处理的几种方式,不是本文所要阐述的内容,有需要的可以参考:《高并发下的接口幂等性解决方案!

一、幂等的分类

1.1、半幂等

例如:

插入一条数据,调用服务A,A服务插入数据库的时候,根据主键冲突策略,发现已经已经存在了,直接返回错误,报已经存在主键了;

这种方式,服务A幂等做的不彻底,只是保证数据不会变更,但是通过返回错误来实现,这样的话,就需要调用方先进行一次查询操作,判断数据是否存在了,如果存在则不插入,如果不存在再调用A服务插入数据了;

1.2、全幂等

相对的,如果调用的服务A,在插入数据的时候,自己先查询一下数据是否已经存在,如果存在直接返回成功,如果不存在则执行插入操作,那么调用方就就直接执行插入操作就可以了,无需自己判断数据是否已经存在了,那么接口A就是全幂等的了;

二、幂等需要关注的几个问题

以下几点并不是需要注意问题的全部,欢迎大家留言补充!

2.1、服务的调用方和服务的提供方幂等键要保证一致,唯一性,并且不变性;

这个很好理解,例如:

  • 服务的调用方以为调用方是按照用户身份证号做幂等的,但其实服务提供方是按照手机号做幂等的,这样就出现问题了;

  • 服务的提供方前段时间还是用A做幂等键的,后边却用B了,说变就变的也是不可以的;

因此,服务调用方在调用服务之前一定要确定好服务提供方幂等键的设置;

2.3、调用方不能单纯的依靠查询来做幂等

例如:用户咔咔点击了两次,两个线程执行,同时执行插入操作,两个线程都先查询,结果某一时间点查询的数据都不存在,然后就执行插入操作了,就插入了两条数据;

在这里插入图片描述
这个时候,就需要加锁处理了或者根据主键冲突策略等方式判断幂等了;

1.1、1.2中举例还是有瑕疵的,大家注意!

2.4、调用方幂等键唯一了,但是其他数据却变了,业务做好处理,具体业务具体分析

这种情况很常见,例如:服务提供方约定以手机号作为幂等键,但是服务的调用方第一次插入数据的时候,手机号是A,其他数据是B,第二次调用的时候,手机号是A,其他数据确是C,那服务提供方到底让不让你插哪?这个就需要根据具体的业务做分析了,如果业务决定,让你插,你就插,不让你插就不能插了!

2.5、幂等键跟随数据做好持久化,做到“有据可依”,禁止幂等键纯内存拼接

这个很好理解,举个例子吧:

插入一条数据,拼接了一个幂等键ABC,你如果不做持久化,数据存储不包含ABC三个字段,那么你下次如何判断数据是否已经存在哪?

2.6、消息幂等处理的几个关键

消息幂等是一个比较复杂的场景,因为消息可能存在的无序性、重复性、延迟,都增加了幂等处理的复杂性,其中重复性则是幂等的时候需要重点考虑的;

2.6.1、重复性

例如:交易系统存在下单、支付、发货行为,交易系统如果多次消费同一笔定金支付成功消息时,由于幂等问题可能导致很多问题:
在这里插入图片描述
一般,我们在发送交易消息的时候,会把 “订单的状态和订单ID” 作为消息体的一部分,然后在接收到消息的时候,根据消息的类型判断是不是下单消息,以及判断当前订单的状态是否是”用户下单“,这样在消息不重复消费的时候,是没有问题的。

如果出现上述情况,用户下单消息重复消费,在接收到用户支付消息的时候订单状态已经被修改为已支付,但是由于用户下单消息重复消费,消息体是没有变化的(状态没有发生变化),就又修改订单状态为待支付状态了,这里显然是不对的。

我们应该做:

我们应该在接收到消息的时候,根据订单ID去数据库查询一下订单此时的状态,然后根据当前的状态判断下一步的操作,并且消息处理的时候还要加锁哦!加锁的维度可以是订单ID!防止并发的时候,出现3.3.2中的情况!

因此,不要把可变值作为幂等的条件,加锁查询订单最新的状态!

2.6.2、无序性

保证消息的顺序消费是比较复杂的,并且成本也很高,一般我们可以根据不同的业务判断消息消费的顺序性的;

例如:用户下单消息=>用户支付消息,顺序的行为是这样消费的。但无序的时候,我们可能先接收到”用户支付消息“然后才会接收到”用户下单消息“。

如果你的业务在接收用户下单消息做的处理不影响主链路的话,则可以直接先处理”用户支付消息“,当在收到”用户下单消息“的时候,查询订单的状态已经变为”已支付“,则直接把消息幂等掉,返回true,结束消息的消费。

但是,如果你的”用户下单消息“有重要的逻辑,必须先消费了之后,才可以消费”用户支付消息“,那我们就需要特别注意了!根据查询出来的订单状态进行判断,判断是否已经消费了”用户下单消息“,当先接收到”用户支付消息“的时候,消息直接重发就可以了,等消费了”用户下单消息“之后,再消费”用户支付消息“。
在这里插入图片描述

2.7、定时任务幂等处理的几个关键

定时任务的幂等需要解决的主要问题就是”重复性“,和消息的重复消费问题大致相同,需要根据查询最新的状态进行业务的处理,这里不做过多说明;


往期热门文章:

1、Stack Overflow上188W+程序员都关注的问题:Java到底是值传递还是引用传递?

2、Dubbo必会的18个面试题!一网打尽!

3、可以提高千倍效率的Java代码小技巧

4、后端开发甩锅指南!

5、答应我,别再if/else走天下了可以吗?
在这里插入图片描述

【视频福利】2T免费学习视频,搜索或扫描上述二维码关注微信公众号:Java后端技术(ID: JavaITWork),和20万人一起学Java!回复:1024,即可免费获取!内含SSM、Spring全家桶、微服务、MySQL、MyCat、集群、分布式、中间件、Linux、网络、多线程,Jenkins、Nexus、Docker、ELK等等免费学习视频,持续更新!

发布了508 篇原创文章 · 获赞 3723 · 访问量 524万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览