在40岁老架构师 尼恩的读者交流群(50+)中,最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、希音、百度、网易、美团的面试资格,遇到很多很重要的面试题:
问题1:你们项目,怎么做幂等设计的?
问题2:接口的幂等性,怎么设计?
问题3:业务订单的幂等性,怎么设计?
问题4:付款请求的幂等性,怎么设计?
问题4:前端重复提交选中的数据,后台只产生一次有效操作,怎么设计?
最近又有小伙伴在面试阿里、网易,都遇到了相关的面试题。
很多小伙伴回答了一些边边角角,但是回答不全面不体系,面试官不满意,面试挂了。
借着此文,尼恩给大家做一下系统化、体系化的梳理,使得大家内力猛增,展示一下雄厚的 “技术肌肉、技术实力”,让面试官爱到 “不能自已、口水直流”,然后实现”offer直提,offer自由”。
当然,这道面试题,以及参考答案,也会收入咱们的 《尼恩Java面试宝典PDF》V161版本,供后面的小伙伴参考,提升大家的 3高 架构、设计、开发水平。
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》的PDF,请到文末公号【技术自由圈】取
所谓幂等性,就是一次操作和多次操作同一个资源,所产生的影响均与一次操作的影响相同。
"幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。
幂等性,用数学语言表达就是:
f(x)=f(f(x))
维基百科的幂等性定义如下:
幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。
这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的,更复杂的操作幂等保证是利用唯一交易号(流水号)实现.
在软件或者系统中,重复使用幂等函数或幂等方法不会影响系统状态,也不用担心重复执行会对系统造成改变。
通俗点说:
一个接口如果幂等,不管被调多少次,只要参数不变,结果也不变。
幂等性是对于写操作来说的,一个写操作,一般都需要保证:
当然,这里仅仅聚焦 幂等。
如果客户端重复调用,服务端会遇到如下的很多问题:
这就是出现了幂等性问题。
按照幂等性要求,需要保证一次请求和多次请求同一个资源产生相同的副作用。
所以:创建订单时,重复调用是否产生两笔订单? 当然不能。
所以:扣减库存时,重复调是否会多扣一次? 当然不能。
这些,都是需要幂等性机制去保障。如果不支持幂等操作,那将会出现以下情况:
等等,非常惨的。
在系统高并发的环境下,很有可能因为网络阻塞等等问题,导致客户端不能及时的收到服务端响应,甚至是调用超时。 这时候用户会重复点击,重复请求。
在消息队列组件中,客户端也有重试机制,如果投递失败/投递超时,则会重新投递。 对于服务端来说,可能会收到重复投递的一份消息。
在RPC组件中,客户端也有重试机制,如果投递失败/投递超时,则会重试调用。 对于服务端来说,可能会重复收到通用的调用。
比如下单的按键在点按之后,在没有收到服务器请求之前,用户还可以被按。
或者,用户的App闪退/人工强退,之后重新打开重新下单
可能会发生重复请求或重试操作的场景,在分布式、微服务架构中是随处可见的。
网络波动:因网络波动,可能会引起重复请求
分布式消息消费:任务发布后,使用分布式消息服务来进行消费
用户重复操作:用户在使用产品时,可能无意地触发多笔交易,甚至没有响应而有意触发多笔交易
未关闭的重试机制:因开发人员、测试人员或运维人员没有检查出来,而开启的重试机制(如Nginx重试、RPC通信重试或业务层重试等)
大致可以分为两大类:
首先,来看看单数据CRUD操作的幂等性保证方案
对于单数据CRUD操作,很多具备天然幂等性
UPDATE goods SET number=number-1 WHERE id=1
UPDATE goods SET number=newNumber WHERE id=1
大家看到,对于单数据CRUD操作, 只有在下面的三个场景,保证幂等即可:
大部分,都是这种场景。
现在的应用,大部分都是微服务的。并且一个操作会涉及到多个数据的并发操作,会通过RPC调用到多个微服务。
分为两种情况:
多数据同步操作,一般是服务端提供一个统一的同步操作api,客户端调用该api完成,直接获得操作结果。
多数据异步操作,由于同步操作性能低,在高并发场景都会同步变异步,于是乎,服务端还要额外提供一个查询操作结果的api,去查询结果。第一次超时之后,调用方调用查询接口,如果查到了就走成功的流程,失败了就走失败的流程。
在抢一份红包的时候,点击了抢,开始异步抢红包。
抢到就有,没抢到就没有。
抢完之后,无论我们重复点击多少次,红包都会提示你已经抢过该红包了。
高并发下单的一个很基本的问题,就是要避免重复订单。
如果用户操作一次,由于超时重试等原因,一看下了两个单,甚至10个重复单。
用户不晕倒在厕所才怪。
在支付场景,支付平台会生成唯一的支付连接,不会再次生成另外的支付连接。
幂等性的的确保方案,非常多,大致如下图所示
如果使用全局唯一ID,就是根据业务的操作和内容生成一个全局ID,在执行操作前先根据这个全局唯一ID是否存在,来判断这个操作是否已经执行。
如果不存在则把全局ID,存储到存储系统中,比如数据库、Redis等。如果存在则表示该方法已经执行。
使用全局唯一ID是一个通用方案,可以支持插入、更新、删除业务操作。
一般情况下,对分布式的全局唯一id,可以参考以下几种方式:
UUID
Snowflake
数据库自增ID
业务本身的唯一约束
业务字段+时间戳拼接
唯一索引(去重表)
这种方法适用于在业务中有唯一标识的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。
这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据写入去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。
这种方法插入并且有唯一索引的情况,比如我们要关联商品品类,其中商品的ID和品类的ID可以构成唯一索引,并且在数据表中也增加了唯一索引。这时就可以使用InsertOrUpdate操作。
这种方法适合在更新的场景中,比如我们要更新商品的名字,这时我们就可以在更新的接口中增加一个版本号,来做幂等:
boolean updateGoodsName(int id,String newName,int version);
在实现时可以如下:
update goods set name=#{newName},version=#{version} where id=#{id} and version<${version}
这种方法适合在有状态机流转的情况下,比如就会订单的创建和付款,订单的付款肯定是在之前,这时我们可以通过在设计状态字段时,使用int类型,并且通过值类型的大小来做幂等,比如订单的创建为0,付款成功为100,付款失败为99。
在做状态机更新时,我们就可以这样控制:
update goods_order set status=#{status} where id=#{id} and status<#{status}
以上就是保证接口幂等性的一些方法。
前面的方案,都是一些基础性的方案。
在实际的业务中,一般会结合起来使用。
在双11和双12的活动中,对于幂等性问题,支付宝团队摸索出来了一个综合性的解决方案:一锁二判三更新。这个方案,可以作为一个比较通用的综合性的幂等解决方案。
何为“一锁二判三更新”?
简单来说就是当任何一个并发请求过来的时候
3.1 如果之前并没有更新,则本次请求可以更新,并完成相关业务逻辑。
3.2 如果之前已经有更新,则本次不能更新,也不能完成业务逻辑。
高并发场景,建议是redis分布式锁,而不是低性能的DB锁,也不是CP型的 Zookeeper锁。
如果普通的redis分布式锁性能太低,该如何?
还可以考虑引入 锁的分段机制, 比如内部分成100端,总体上,就大概能线性提升 100倍。
幂等性判断,就是 进行 数据检查。
可以基于状态机、流水表、唯一性索引等等前面介绍的 基础方案,进行重复操作的判断。
如果通过了第二步的幂等性判断, 说明之前没有执行过更新操作。
那么就进入第三步,进行数据的更新,将数据进行持久化。
操作完成之后, 记得释放锁, 结束整个流程。
关于redis分布式锁、 Zookeeper锁、分段锁的内容,请参见5000页《尼恩Java面试宝典》的相应的专题。
以上的内容,如果大家能对答如流,如数家珍,基本上 面试官会被你 震惊到、吸引到。
最终,让面试官爱到 “不能自已、口水直流”。 offer, 也就来了。
其实, “offer自由” 不难实现, 前段时间一个跟尼恩卷了2年的武汉小伙,9年经验, 在年底大裁员的极度严寒/痛苦被裁的背景下, offer拿到手软, 实现真正的 “offer自由” 。
在面试之前,建议大家系统化的刷一波 5000页《尼恩Java面试宝典PDF》,里边有大量的大厂真题、面试难题、架构难题。很多小伙伴刷完后, 吊打面试官, 大厂横着走。
在刷题过程中,如果有啥问题,大家可以来 找 40岁老架构师尼恩交流。
尼恩一直深耕技术,不是在研究技术,就是在研究技术的路上,加尼恩微信之后不一定立马通过, 但是,最多1-2小时就会审核的。
特别要说的是:很多小伙伴简历投出去后如泥牛入海、不冒一泡、没有面试机会。
遇到这种难题,可以找尼恩来改简历、做帮扶。
另外,遇到架构升级、晋升受阻、职业打击等职业难题,也可以找尼恩取经, 可以省去太多的折腾,省去太多的弯路。
尼恩已经指导了大量的小伙伴上岸,前段时间指导一个40岁+被裁小伙伴上岸,拿到了一个年薪100W的offer。
……完整版尼恩技术圣经PDF集群,请找尼恩领取
《尼恩 架构笔记》《尼恩高并发三部曲》《尼恩Java面试宝典》PDF,请到下面公号【技术自由圈】取↓↓↓