专栏首页JavaEdge突破Java面试(38)-分布式服务接口的幂等性
原创

突破Java面试(38)-分布式服务接口的幂等性

1 面试题

分布式服务接口的幂等性如何设计(比如不能重复扣款)?

2 考点分析

从这开始,面试官就已经进入了实际的生产问题的面试了

一个分布式系统中的某个接口,要保证幂等性,如何保证?

这个事,其实是你做分布式系统的时候必须要考虑的一个生产环境的技术问题.为什么呢?

假如你有个服务提供一个接口,这服务部署在5台机器上,有个付款接口.

然后用户在前端操作时,不知为啥,一个订单不小心发起了两次支付请求,然后这俩请求分散在了这个服务部署的不同的机器上,这下好了,结果一个订单扣款扣两次,尴尬了!

或者是订单系统调用支付系统进行支付,结果不小心网络超时,然后订单系统走了前面我们看到的那个重试机制,给你重试了一把,好,支付系统收到一个支付请求两次,而且因为负载均衡算法落在了不同的机器上,尴尬了!

  • 分布式系统接口的幂等性问题

所以你肯定得知道这事儿,否则你做出来的分布式系统恐怕容易埋坑!

网络问题很常见,100次请求,都ok

1万次,可能1次是超时会重试

10万,10次;100万,100次;如果有100个请求重复了,你没处理,导致订单扣款2次,100个订单都扣错了;每天被100个用户投诉;一个月被3000个用户投诉

这个不是技术问题,没有通用的一个方法,得结合业务来看应该如何保证幂等性.

3 幂等性

所谓幂等性,简而言之,就是一个接口,多次发起同一个请求,接口得保证结果是准确的,比如不能多扣款,不能多插入一条数据,不能将统计值多加了1.

保证幂等性主要有如下几点

  • 对于每个请求必须有一个唯一的标识 举个例子:订单支付请求,肯定得包含订单id,一个订单id最多支付一次
  • 每次处理完请求后,须有一个记录标识该请求已被处理 比如说常见的方案是在MySQL中记录个状态字段 比如支付之前记录一条这个订单的支付流水
  • 每次接收请求需要进行判断之前是否处理过 比如说,如果有一个订单已经支付了,就已经有了一条支付流水,那么如果重复发送这个请求,则此时先插入支付流水,orderId已存在,唯一键约束生效,报错插入不进去的。然后你就不用再扣款了.

上面只是举个例子,实际运作过程中,要结合自己的业务来,比如说用redis,用orderId作为唯一键。只有成功插入这个支付流水,才可以执行实际的支付扣款。

要求是支付一个订单,必须插入一条支付流水,order_id建立一个唯一键unique key

你在支付一个订单前,先插入一条支付流水,order_id就已经传过去了

你就可以写一个标识到Redis中,set order_id payed,当重复请求过来时,先查Redis的order_id对应的value,若为payed说明已支付,就别重复支付了!

然后呢,你再重复支付这个订单的时候,你写尝试插入一条支付流水,数据库给你报错了,说unique key冲突了,整个事务回滚就可以了

来保存一个是否处理过的标识也可以,服务的不同实例可以一起操作Redis.

参考

  • 《Java工程师面试突击第1季-中华石杉老师》Github

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Redis集群实现分布式锁的正确方式

    上文我们介绍的 Redis实现分布式锁的正确方式 是 redis 单机的方式,所以本篇要基于 redis 集群做分布式锁,我们使用 Redisson

    胖虎
  • Redis + Lua 实现分布式应用限流

    今天讲的 redis+lua 解决分布式限流 任何框架都能用,只要能集成 redis就可以,不管是微服务 dubbo、springcloud,还是直接用 spr...

    胖虎
  • JAVA高并发 Redis+Lua限流实战

    但是我们也知道,限流器在每次请求令牌和放入令牌操作中,存在一个协同的问题,即获取令牌操作要尽可能保证原子性,否则无法保证限流器是否能正常工作。在RateLimi...

    小东啊
  • Mac系统搭建Redis集群模式

    其次就是版本差距太大,集群模式必须是3.x以上版本才可以,所以呢,百度上的东西基本都是3.x,我想说要玩就玩别人很少玩的,我非要搞个4.x版本瞧瞧,当然我没有敢...

    胖虎
  • 这简历一看就是包装过的,你听过这句话吗?

    Coody 老师根据自己的经验写下了这篇文章,谁都不是天才,包装无可厚非,切勿对号入座!

    良月柒
  • Discuz!开启php-redis 扩展,让你的BBS更快

    5.Discuz需要编译Config/config_global.php配置才可以开启,默认是不打开的。

    椰果笔记
  • 我的第6个京东618

    今年是我的第6个618,因为入职的时间比较"合适",使得我经历了每年两次完整的大促备战。那年还在北辰,618的当晚,我记忆的很清晰,接近凌晨1点左右的时候,我们...

    王新栋
  • Redis删除特定前缀key的优雅实现

    Redis中没有批量删除特定前缀key的指令,但我们往往需要根据前缀来删除,那么究竟该怎么做呢?可能你一通搜索后会得到下边的答案

    小尘哥
  • ELK日志分析方案

    1.在微服务服务器上部署Logstash,作为Shipper的角色,对微服务日志文件数据进行数据采集,将采集到的数据输出到Redis消息队列。

    IT技术小咖
  • 『互联网架构』软件架构-Spring boot集成三方中间件(88)

    3.src/main/resources/templates增加error.html

    IT故事会

扫码关注云+社区

领取腾讯云代金券