掌握分布式事务锁,这个大厂实战订单锁你一定要会

栏目: 后端 · 发布时间: 5年前

内容简介:目前几乎很多大型网站及应用都是分布式部署的,分布式场景中我们也都会遇到一个非常重要的问题:数据一致性。正如分布式的CAP理论说的一样:“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。”所以,很多系统在设计之初就要对这三者进行取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可

掌握分布式事务锁,这个大厂实战订单锁你一定要会

分布式趋势

掌握分布式事务锁,这个大厂实战订单锁你一定要会

目前几乎很多大型网站及应用都是分布式部署的,分布式场景中我们也都会遇到一个非常重要的问题:数据一致性。正如分布式的CAP理论说的一样:“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。”所以,很多系统在设计之初就要对这三者进行取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支撑,比如分布式事务、分布式锁、定时任务调度等。尽管 Java 提供了很多并发处理API,但这些API在分布式场景中就显得无能为力了。

所以针对分布式锁的实现我们需要借助别的工具,目前比较常用的有以下几种方案:

  1. 基于数据库实现分布式锁
  2. 基于缓存(redis,memcached,tair)实现分布式锁
  3. 基于Zookeeper实现分布式锁

本篇发文我们主要说下基于 Redis 的分布式锁实战。

实际编写代码之前,我们说下首要条件

分布式锁可用的四个条件:

  1. 互斥性。在任意时刻,只有一个客户端能持有锁。
  2. 不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  3. 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。
  4. 解铃还须系铃人。加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

分布式锁实战步骤:

编写ILock接口

掌握分布式事务锁,这个大厂实战订单锁你一定要会

编写ILock接口实现

掌握分布式事务锁,这个大厂实战订单锁你一定要会

掌握分布式事务锁,这个大厂实战订单锁你一定要会

掌握分布式事务锁,这个大厂实战订单锁你一定要会

LockGetter抽象类

掌握分布式事务锁,这个大厂实战订单锁你一定要会

掌握分布式事务锁,这个大厂实战订单锁你一定要会

从图示我们可以看出,通过LockGetter抽象类进行具体的加锁成功或则失败的具体业务走向。这一个思想同学们要谨记于心。能够熟练应用的话,他会使你在编程之路上走的更加顺畅。

此外,可以看到,我们实际加锁就一行代码:jedis.set(fieldKey, value, "NX", "EX", seconds);,这个set()方法一共有五个形参:

第一个参数为key,我们使用key来当锁,因为key是唯一的。

第二个参数为value,我们传的是requestId,很多童鞋可能不明白,有key作为锁不就够了吗,为什么还要用到value?原因就是我们在上面讲到可靠性时,分布式锁要满足第四个条件解铃还须系铃人,通过给value赋值为requestId,我们就知道这把锁是哪个请求加的了,在解锁的时候就可以有依据。requestId可以使用UUID.randomUUID().toString()方法生成。

第三个参数为nxxx,这个参数我们填的是NX,意思是SET IF NOT EXIST,即当key不存在时,我们进行set操作;若key已经存在,则不做任何操作;

第四个参数为expx,这个参数我们传的是PX,意思是我们要给这个key加一个过期的设置,具体时间由第五个参数决定。

第五个参数为time,与第四个参数相呼应,代表key的过期时间。

总的来说,执行上面的set()方法之后会出现两种情况:

  1. 当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,同时value表示加锁的客户端。
  2. 锁已经存在,redis不做任何操作。

总结:

使用缓存来实现分布式锁优点:

  1. 可以提供更好的性能,同时很多缓存服务都是集群部署的,可以避免单点问题。
  2. 很多缓存服务都提供了可以用来实现分布式锁的方法,比如redis的setnx方法等。
  3. 缓存服务也都提供了对数据的过期自动删除的支持,可以直接设置超时时间来控制锁的释放。

使用缓存实现分布式锁尽管性能好,实现起来较为方便。但也不是没有缺点,有时候我们的程序内部出现异常后可能会发生死锁,这就需要开发时候注意代码编写,后续测试人员测试时候测试案例要尽可能覆盖。

写在最后

最后,欢迎做Java的工程师朋友们加入Java高级架构进阶Qqun:963944895

群内有技术大咖指点难题,还提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)

比你优秀的对手在学习,你的仇人在磨刀,你的闺蜜在减肥,隔壁老王在练腰, 我们必须不断学习,否则我们将被学习者超越!

趁年轻,使劲拼,给未来的自己一个交代!

掌握分布式事务锁,这个大厂实战订单锁你一定要会


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Python Web开发:测试驱动方法

Python Web开发:测试驱动方法

Harry J.W. Percival / 安道 / 人民邮电出版社 / 2015-10 / 99

本书从最基础的知识开始,讲解Web开发的整个流程,展示如何使用Python做测试驱动开发。本书由三个部分组成。第一部分介绍了测试驱动开发和Django的基础知识。第二部分讨论了Web开发要素,探讨了Web开发过程中不可避免的问题,及如何通过测试解决这些问题。第三部分探讨了一些高级话题,如模拟技术、集成第三方插件、Ajax、测试固件、持续集成等。本书适合Web开发人员阅读。一起来看看 《Python Web开发:测试驱动方法》 这本书的介绍吧!

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具