API接口非幂等性问题及使用redis实现简单的分布式锁

        在我们平台中,开放了一些接口给其它系统或第三方应用调用。

        幂等性问题主要是在创建对象且这些对象不能重复的时候产生,比如创建用户,这个时候,应该说 幂等性不是问题,非幂等性才是问题。

        创建对象,一般使用HTTP的POST方法,在restful设计中,POST方法是非幂等的,不过我们使用POST方法不一定就非幂等。比如对内我们自己调用是可以重复创建的(非幂等),但是对外开放,不能重复创建(幂等)。


        在创建对象的时候,为了避免非幂等产生的问题,应该如何做呢?


        请求的时候要带上一个标识,这个标识要是唯一、可信的。接收请求后,先查询这个标识是否已经存在,如果不存在则创建一个对象;如果存在则告知已经创建。

        比如使用手机号码创建用户,这个手机号码可以作为创建用户的标识,如果要可信,发一个验证码验证一下。创建时,后台肯定先要验证一个这个手机有没有被注册,这就防止重复注册了。

        那在集群或分布式环境中,虽然请求中有唯一标识,但还是会有问题。比如连续两次请求,很快很快,都使用同一标识,那么处理不好就创建两个对象了。因为第一个请求在没有保存对象时,第二个请求发现还没有创建,又创建一个对象。嗯,我们就出现这个不专业的问题。

        两个请求可能在不同应用服务器执行,创建的两个对象保存在不同数据库上,没办法使用锁,没有分布式事务,也无法保证操作时序一致。

        使用zookeeper/etcd等分布式协调服务,可以解决此问题。目前我们没有搭建这类服务,因此只能使用其它方式,当然也是找一个合适的第三方来保证。对于分布式并发的锁处理,核心是需要一个第三方,也就是仲裁方,满足:

        1.唯一的。同一时间只有集群中的一个主节点提供仲裁。

        2.可靠的。不能说挂就挂,一般使用集群,至少要主备吧。当主节点挂了,客户端连接其它节点时,数据不会丢。

        3.够快的。或者叫高性能。

        然后就找到了redis,在对本例中要解决的问题来说,现成、简单、易用,因为redis服务常见,也已经在项目中部署。使用redis的incr方法可以帮我们解决这个重复创建问题。使用同一台redis(主从),其原子性保证我们不需要担心并发。创建时,把唯一标识作为key并incr一下,并获取返回值,如果是1,那就说明没有创建过此对象,如果大于1,那就说明已经创建过了。同时key缓存时间保证对象保存到数据库即可。

        在主备的情况下,除非redis在写到主库时,数据同时写到备库再返回结果(强一致性),否则处理分布式锁并不可靠。但是redis的主备同步好像是采用异步的,弱一致性同步的,可能出现的问题是,第一个客户端刚写到redis主节点还没有同步到备节点就挂了,第二个客户端只好访问备redis,发现没有数据(没有锁),并重复获取锁,这样有两个客户端获取到锁了。

        在开放接口时考虑非幂等性问题,实现时还要考虑分布式环境,防止重复创建对象,以上是产生的问题和解决的思路。

         

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值