安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

Java接口幂等性设计场景解决方案v1。0

10月10日 乔了了投稿
  1面试实际开发场景11面试场景题目
  分布式服务接口的幂等性如何设计(比如不能重复扣款)?12题目分析
  一个分布式系统中的某个接口,要保证幂等性,如何保证?这个事,其实是你做分布式系统的时候必须要考虑的一个生产环境的技术问题,为什么呢?
  实际案例1:
  假如你有个服务提供一个付款业务的接口,而这个服务分别部署在5台服务器上,然后用户在前端操作时,不知道为啥,一个订单不小心发起了两次支付请求,然后这俩请求分散在了这个服务部署的不同的服务器上,这下好了,一个订单扣款扣了两次。
  实际案例2:
  订单系统调用支付系统进行支付,结果不消息网络,然后订单系统走了前面我们看到的重试retry机制,那就给你重试一次吧,那么支付系统收到了一个支付请求两次,而且因为负载均衡算法落在了不同的机器上。
  小结:
  所以你必须得知道这事,否则你做出来的分布式系统恐怕很容易埋坑!2幂等性介绍21概念:
  用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。
  举个简单的例子:那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常了,此时钱已经扣了,用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。在以前的单应用系统中,我们只需要对数据操作加入事务即可,发生错误的时候立即回滚,但是再响应客户端的时候也有可能网络中断或者异常等等情况。22产生幂等性问题的原因:网络问题用户误操作恶意操作,用户点击了多次网络问题,微服务重试retry网络问题很常见,100次请求,都1万次请求可能1次超时会重试;10万次可能10次超时会重试,100万次可能100次超时会重试;如果100个请求重复了,你没处理,导致订单扣款2次,100个订单都扣错了,每天被100个用户投诉,一个月被3000个用户投诉。23使用幂等性的场景前端重复提交:前端瞬时点击多次造成表单重复提交接口超时重试:接口可能会因为某些原因而调用失败,处于容错性考虑会加上失败重试的机制。如果接口调用一半,再次调用就会因为脏数据的存在而产生异常消息重复消费:在使用消息中间件来处理消息队列,且手动ack确认消息被正常消费时。如果消费者突然断开链接,那么已经执行了一半的消息会重新放回队列。被其他消费者重新消费时就会导致结果异常,如数据库重复数据,数据库数据冲突,资源重复等请求重发:网络抖动引发的nginx重发请求,造成重复调用。3幂等性的解决方案31Insert接口幂等性1。使用分布式锁保证幂等性
  秒杀场景下,一个用户只能购买同一商品一次的解决方法:采用用户ID商品ID,存储到redis中,使用redis中的setNX操作,等待自然过期。2。使用token机制保证幂等性
  用户注册时,用户点击注册按钮多次,是不是会注册多个用户?我们可以在用户进入注册页面后由后台生成一个token,传给前端页面,用户在点击提交时,将token带给后台,后台使用该token作为分布式锁,setNX操作,执行成功后不释放锁,等待自然过期。3。使用mysqluniquekey保证幂等性
  用户注册时,用户点击注册按钮多次,是不是会注册多个用户?我们可以使用手机号作为mysql用户表唯一key。也就是一个手机号只能注册一次。32Update接口幂等性
  update操作可能存在幂等性的问题:
  1。用户更改个人信息,疯狂点击按钮,不会发生幂等性问题,因为数据始终为修改后的数据。
  2。用户购买商品,用户在点击后,网络出现问题,可能再次点击,这样就会出现幂等性问题,导致购买了多次,可以使用乐观锁updateordersetcountcount1,versionversion1whereid1andversion133Delete接口幂等性
  根据唯一id删除不会出现幂等性问题,因为第二次删除的时候mysql中已经不存在该数据34Select接口幂等性
  查询操作不会改变数据,所以是天然的幂等性操作。35混合操作(一个接口包含多种操作)
  使用Token机制,或使用Token分布式锁的方案来解决幂等性问题。4幂等性解决方案实现思路41Token机制实现
  通过Token机制实现接口的幂等性,这是一种比较通用性的实现方法。
  具体流程步骤:客户端会先发送一个请求去获取Token,服务端会生成一个全局唯一的ID作为Token保存在Redis中,同时把这个ID返回给客户端;客户端第二次调用业务请求的时候必须携带这个T服务端会校验这个Token,如果校验成功,则执行业务,并删除Redis中的T如果校验失败,说明Redis中已经没有对应的Token,则表示重复操作,直接返回指定的结果给客户端。42基于MySQL实现
  通过MySQL唯一索引的特性实现接口的幂等性。
  具体流程步骤:建立一张去重表,其中某个字段需要建立唯一索引;客户端去请求服务端,服务端会将这次请求的一些信息插入这张去重表中;因为表中某个字段带有唯一索引,如果插入成功,证明表中没有这次请求的信息,则执行后续的业务逻辑;如果插入失败,则代表已经执行过当前请求,直接返回。43基于Redis实现
  通过Redis的SETNX命令实现接口的幂等性。
  SETNXkeyvalue:当且仅当key不存在时将key的值设为若给定的key已经存在,则SETNX不做任何动作。设置成功时返回1,否则返回0。
  具体流程步骤:客户端先请求服务端,会拿到一个能代表这次请求业务的唯一字段;将该字段以SETNX的方式存入Redis中,并根据业务设置相应的超时时间;如果设置成功,证明这是第一次请求,则执行后续的业务逻辑;如果设置失败,则代表已经执行过当前请求,直接返回。5幂等性解决方案案例实现51基于Token机制的实现511实现思路
  为需要保证幂等性的每一次请求创建一个唯一的标识token,先获取token,并将此token存入到redis,请求接口时,将此token放在header或者作为请求参数请求接口,后端接口判断redis中是否存在此如果存在,则正常处理业务逻辑,并从redis中删除此token,那么,如果是重复请求,由于token已经被删除,则不能能够通过校验,返回重复提交如果不存在,说明参数不合法或者是重复请求,返回提示即可512请求流程当页面加载的时候通过接口获取token当访问接口时,会经过拦截器,如果发现该接口中有自定义的幂等性注解,说明该接口需要验证幂等性(查看请求头里是否有keytoken的值,如果有,并且删除成功,那么接口就访问成功,否则为重复提交;如果发现该接口没有自定义的幂等性注解,则放行。513代码演示1、使用的技术springBootredis自定义幂等性注解拦截器请求拦截Jmeter压测工具2、创建项目
  3、导入pom。?xmlversion1。0encodingUTF8?projectxmlnshttp:maven。apache。orgPOM4。0。0xmlns:xsihttp:www。w3。org2001XMLSchemainstancexsi:schemaLocationhttp:maven。apache。orgPOM4。0。0http:maven。apache。orgxsdmaven4。0。0。xsdmodelVersion4。0。0modelVersiongroupIdorg。examplegroupIdspringBootidempotentartifactIdversion1。0SNAPSHOTversionpropertiesmaven。compiler。source8maven。compiler。sourcemaven。compiler。target8maven。compiler。targetpropertiesparentgroupIdorg。springframework。bootgroupIdspringbootstarterparentartifactIdversion2。3。2。RELEASEversionparentdependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependencydependencygroupIdorg。springframework。bootgroupIdspringbootstarterdataredisartifactIddependencydependenciesproject4、自定义注解
  该注解的目的是为了实现幂等性的校验,即添加了该注解的接口要实现幂等性验证packagecom。ldp。idempotent。importjava。lang。annotation。;自定义注解说明:添加了该注解的接口要实现幂等性验证Target({ElementType。TYPE,ElementType。METHOD})Retention(RetentionPolicy。RUNTIME)DocumentedpublicinterfaceApiIdempotentAnn{booleanvalue()}5、幂等性拦截器packagecom。ldp。idempotent。importcom。ldp。idempotent。annotation。ApiIdempotentAimportorg。springframework。beans。factory。annotation。Aimportorg。springframework。data。redis。core。StringRedisTimportorg。springframework。stereotype。Cimportorg。springframework。web。method。HandlerMimportorg。springframework。web。servlet。ModelAndVimportorg。springframework。web。servlet。handler。HandlerInterceptorAimportjavax。servlet。http。HttpServletRimportjavax。servlet。http。HttpServletRimportjava。io。PrintWimportjava。lang。reflect。M幂等性拦截器ComponentpublicclassApiIdempotentInceptorextendsHandlerInterceptorAdapter{AutowiredprivateStringRedisTemplateredisT前置拦截器在方法被调用前执行。在该方法中可以做类似校验的功能。如果返回true,则继续调用下一个拦截器。如果返回false,则中断执行,也就是说我们想调用的方法不会被执行,但是你可以修改response为你想要的响应。OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{如果hanler不是和HandlerMethod类型,则返回trueif(!(handlerinstanceofHandlerMethod)){}转化类型finalHandlerMethodhandlerMethod(HandlerMethod)获取方法类finalMethodmethodhandlerMethod。getMethod();判断当前method中是否有这个注解booleanmethodAnnmethod。isAnnotationPresent(ApiIdempotentAnn。class);如果有幂等性注解if(methodAnnmethod。getAnnotation(ApiIdempotentAnn。class)。value()){需要实现接口幂等性检查token1。获取请求的接口方法查看当前接口的方法之上是否有自定义的注解ApiIdempotentAnn如果说包含了,则认为该接口是要进行幂等性校验的接口检验token如果说有,则访问成功,执行逻辑业务,要删除redis中的token如果说没有,则表示重复调用如果说没有包含了,则直接放行checkToken(request);如果token有值,说明是第一次调用if(result){则放行returnsuper。preHandle(request,response,handler);}else{如果token没有值,则表示不是第一次调用,是重复调用response。setContentType(charsetutf8);PrintWriterwriterresponse。getWriter();writer。print(重复调用);writer。close();response。flushBuffer();}}否则没有该自定义幂等性注解,则放行returnsuper。preHandle(request,response,handler);}检查tokenprivatebooleancheckToken(HttpServletRequestrequest){从请求头对象中获取tokenStringtokenrequest。getHeader(token);如果不存在,则返回false,说明是重复调用if(tokennull。equals(token)){}否则就是存在,存在则把redis里删除tokenreturnredisTemplate。delete(token);}后置,暂时没用OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{super。postHandle(request,response,handler,modelAndView);}}6、MVC配置文件packagecom。ldp。idempotent。importcom。ldp。idempotent。intceptor。ApiIdempotentIimportorg。springframework。beans。factory。annotation。Aimportorg。springframework。context。annotation。Cimportorg。springframework。web。servlet。config。annotation。InterceptorRimportorg。springframework。web。servlet。config。annotation。WebMvcCmvc配置ConfigurationpublicclassMvcConfigimplementsWebMvcConfigurer{AutowiredprivateApiIdempotentInceptorapiIdempotentI添加自定义拦截器到Springmvc配置中,拦截所有请求addInterceptor需要一个实现HandlerInterceptor接口的拦截器实例addPathPatterns用于设置拦截器的过滤路径规则;addPathPatterns()对所有请求都拦截excludePathPatterns:用于设置不需要拦截的过滤规则OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry。addInterceptor(apiIdempotentInceptor)。addPathPatterns();}}7、接口实现packagecom。ldp。idempotent。importcom。ldp。idempotent。annotation。ApiIdempotentAimportorg。springframework。beans。factory。annotation。Aimportorg。springframework。data。redis。core。StringRedisTimportorg。springframework。web。bind。annotation。GetMimportorg。springframework。web。bind。annotation。RestCimportjava。util。UUID;importjava。util。concurrent。atomic。AtomicIRestControllerpublicclassApiController{AutowiredprivateStringRedisTemplatestringRedisT前端获取token,然后把该token放入请求的header中returnGetMapping(getToken)publicStringgetToken(){StringtokenUUID。randomUUID()。toString()。substring(1,9);stringRedisTemplate。opsForValue()。set(token,1);}定义int类型的原子类的类AtomicIntegernumnewAtomicInteger(100);主业务逻辑,num,并且加了自定义接口returnGetMapping(submit)ApiIdempotentAnnpublicStringsubmit(){numnum。decrementAndGet();}查看num的值returnGetMapping(getNum)publicStringgetNum(){returnString。valueOf(num。get());}}8、PostMan测试获取token
  浏览器访问:http:localhost:9090getToken,获取token的值
  执行幂等性业务接口第一次,在postman中调用当前接口,并在请求头中设置token
  第二次,再次postman中访问该业务接口,显示重复调用的提示
  查看num的值得接口
  浏览器访问:http:localhost:9090getNum
  9Jmeter压力测试工具测试
  使用方法参考Jmeter压力测试工具使用说明v1。010小结
  通过以上代码演示了解到,本案例对submit接口方法使用了基于token的幂等性解决方案,也就是当前submit接口方法只能调用一次,如果由于网络抖动或者网络异常出现多点或者点击多次的情况,就会出现报错提示,不允许调用当前接口,那么也就解决了当前业务接口幂等性的问题。
投诉 评论 转载

艾灸不当,火上浇油!艾灸需根据体质,对症下药,否则越灸越伤众所周知,三伏是最适合艾灸的季节。尤其像风湿、哮喘、鼻炎等慢性疾病,夏季的艾灸效果最好,所以我们一直强调冬病夏治。但任何中医手段,都是有适应症的,即使西医的抗生素,也是分……甜美啊NBA最美星二代!这一声岳父我先叫上了在今年5月中旬,休斯顿媒体人MarkBerman爆料,火箭助教霍纳塞克下赛季不会重返球队。霍纳塞克曾执教过太阳与尼克斯两队,而后在2020年12月,他接受了塞拉斯团队的邀……余生,做个简单的人时光荏苒,岁月蹉跎,不经意间人生已经过去了大半。那些年少不识愁滋味的日子,那些为赋新词强说愁好时光,青葱岁月里的嬉笑欢闹,在岁月的深处,渐渐变成了一张张发黄的照片,总是在不经意……欧盟颁出最严制裁综合外媒消息,经过多日协商,30日,欧盟各成员国领导人同意禁止超过三分之二的俄罗斯石油进口,对包括匈牙利在内的坚持反对石油禁运的内陆欧盟国家做出了让步。德媒称,这是俄乌冲突3个……游历红色通道走进魅景侗情湖南省通道侗族自治县奋力打造国家全域大型侗寨山水实景演出《戊梁恋歌》吴大泽摄这里有闻名遐迩的旅游品牌。湖南省通道侗族自治县(以下简称:通道县)拥有国家4A级旅游景区4个、国家3A级旅游景区3个,建成旅游重点……Java接口幂等性设计场景解决方案v1。01面试实际开发场景11面试场景题目分布式服务接口的幂等性如何设计(比如不能重复扣款)?12题目分析一个分布式系统中的某个接口,要保证幂等性,如何保证?这个事,其实是……三年前256G版本的iPhone11,放在2022年,相当于还记得三年前iPhone11刚刚发布的时候,我还用的是iPhone8,iPhone11是第一部支持双卡双待的苹果手机,并且iPhone11系列也是首次推出紫色款,给了果粉们特别……朱芳雨无能为力,广东男篮不养闲人,CBA八冠王苏伟被曝或已离朱芳雨无能为力,广东男篮不养闲人,CBA八冠王苏伟被曝即将离队。目前的CBA仍旧处于休赛期,由于球员转会窗口正式开启,所以一些面临合同到期的热门球员自然自信了不少球队的关注。据……汉正街经济实体与电商的碰撞如今的天下大势,是美国以美元为结算方式统筹货币体系,也就是,全世界人们为美国买单,以美元为货币结算方式的货币体系已经统治了全球金融好几百年,也就是说,美国人不怕与其他国家合作,……新机iPhone14全系配色曝光红米Note12要来了华为手iPhone14或支持全新可变色紫色4月23日消息,据MacRumors报道,一些消息来源表示,iPhone14系列将提供更新的颜色选择,包括全新的紫色,并采用新的Tru……年夜饭必备的菜,寓意红火又好运,做法很简单,上桌一定惊艳大家小昕代表《昕味集》祝大家狗年快乐,大吉大利!在新的一年中,好运长似龙、生活处处同、事业爱情双双红、家庭和睦多兴隆!那今天的家宴,小昕为您准备好了,直接找这个来做就好,荤素……苹果iPhone14系列迎5年来巨变,库克要砍掉刘海与手机卡随着时间进入2022年,在大家欢度新年的同时,为喜欢苹果手机的果粉送上新消息,今年的iPhone14系列将迎来5年来最大变化,屏幕设计将与安卓机看齐,有望首次采用打孔屏设计,大……
伤病打不败我的意志,家庭不幸使我变得强大,女篮姑娘勒布朗李梦全球最大中国开建110米口径全向可动射电望远镜圣诞节活动方案怎么写人生不顺时,做好这几件事,好运会主动找你本田锐减19,日产大跌20,马自达更惨,日系车为何在华失宠?人生赢家!郜林广州豪宅1。29亿卖出,16年4000万买下,印江,梵净山深处隐藏着的一个美得令人窒息的小县城自由职业5年,电竞玩家小杨哥选择了不一样的电竞生活西施王挑战赛巅峰第一竟被杰7吊打,全胜喜提西施王称号华为鸿蒙系统麒麟芯片5000mAh大音量,128GB仅售11庐山植物园游园随笔,缅怀三老和陈寅恪大师假期调休疲倦了我的身心生活的理解我爱这片土地初中作文超帅超有魅力的扣扣名字请给我壹碗孟婆汤解渴如何成为一名作家我家的中秋节民事诉讼法中特别程序的特点有哪些林肯的成长的名人故事独居老人的心理特点深圳二手房买卖需要注意哪些事项唐宫秘史晚年唐太宗为什么想要杀掉武则天工信部部署2022年工作,明确把工业稳增长摆在最重要的位置618大促realme获京东手机品牌官方旗舰店单品销售额第一

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利