线程安全告诉我们无状态和原子类型是线程安全的对于分布式而言 我们的状态修改只能一个入口并且是加锁的这样才能保证在分布式环境下数据的安全可靠。
一、为什么要使用分布式锁
我们在开发应用的时候如果需要对某一个共享变量进行多线程同步访问的时候可以使用我们学到的Java多线程的18般武艺进行处理并且可以完美的运行毫无Bug
注意这是单机应用也就是所有的请求都会分配到当前服务器的JVM内部然后映射为操作系统的线程进行处理而这个共享变量只是在这个JVM内部的一块内存空间
后来业务发展需要做集群一个应用需要部署到几台机器上然后做负载均衡大致如下图
上图可以看到变量A存在JVM1、JVM2、JVM3三个JVM内存中这个变量A主要体现是在一个类中的一个成员变量是一个有状态的对象例如UserController控制器中的一个整形类型的成员变量如果不加任何控制的话变量A同时都会在JVM分配一块内存三个请求发过来同时对这个变量操作显然结果是不对的即使不是同时发过来三个请求分别操作三个不同JVM内存区域的数据变量A之间不存在共享也不具有可见性处理的结果也是不对的
如果我们业务中确实存在这个场景的话我们就需要一种方法解决这个问题
为了保证一个方法或属性在高并发情况下的同一时间只能被同一个线程执行在传统单体应用单机部署的情况下可以使用Java并发处理相关的API(如ReentrantLock或Synchronized)进行互斥控制。在单机环境中Java中提供了很多并发处理相关的API。但是随着业务发展的需要原单体单机部署的系统被演化成分布式集群系统后由于分布式系统多线程、多进程并且分布在不同机器上这将使原单机部署情况下的并发控制锁策略失效单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM的互斥机制来控制共享资源的访问这就是分布式锁要解决的问题
二、分布式锁应该具备哪些条件
在分析分布式锁的三种实现方式之前先了解一下分布式锁应该具备哪些条件
1、在分布式系统环境下一个方法在同一时间只能被一个机器的一个线程执行 2、高可用的获取锁与释放锁 3、高性能的获取锁与释放锁 4、具备可重入特性 5、具备锁失效机制防止死锁 6、具备非阻塞锁特性即没有获取到锁将直接返回获取锁失败。
三、分布式锁的三种实现方式
目前几乎很多大型网站及应用都是分布式部署的分布式场景中的数据一致性问题一直是一个比较重要的话题。分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性Consistency、可用性Availability和分区容错性Partition tolerance最多只能同时满足两项。”所以很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中都需要牺牲强一致性来换取系统的高可用性系统往往只需要保证“最终一致性”只要这个最终时间是在用户可以接受的范围内即可。
在很多场景中我们为了保证数据的最终一致性需要很多的技术方案来支持比如分布式事务、分布式锁等。有的时候我们需要保证一个方法在同一时间内只能被同一个线程执行。
- 基于数据库实现分布式锁
- 基于缓存Redis等实现分布式锁
- 基于Zookeeper实现分布式锁
这三种方式对比
从理解的难易程度角度从低到高
- 数据库 > 缓存 > Zookeeper
从实现的复杂性角度从低到高
- Zookeeper > 缓存 > 数据库
从性能角度从高到低
- 缓存 > Zookeeper > 数据库
从可靠性角度从高到低
- Zookeeper > 缓存 > 数据库
———————————————— 版权声明本文为CSDN博主「1Vincent」的原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接及本声明。 原文链接https://blog.csdn.net/wuzhiwei549/article/details/80692278
【本文由:香港云服务器 http://www.558idc.com/ne.html网络转载请说明出处】