夜深人静了,我们来学学分布式锁

夜深人静了,我们来学学分布式锁

作者:故里 2020-11-26 06:38:14

开发

前端

分布式 记录一下今天的文章开始写的时间00:53,夜深人静了,我们来学一下分布式锁,我们要悄悄地学习,然后经验所有人。

[[354141]]

本文转载自微信公众号「故里学Java」,作者故里 。转载本文请联系故里学Java公众号。  

记录一下今天的文章开始写的时间00:53,夜深人静了,我们来学一下分布式锁,我们要悄悄地学习,然后经验所有人。

什么是分布式锁?分布式锁又可以解决哪些问题呢?

在我们的系统还没有使用分布式架构的时候,我们可以用同步锁或者Lock锁,来保证多线程并发的时候,同一时间只有一个线程修改共享变量或者执行代码块,但是当我们现在大部分系统都是分布式集群部署的,单纯的同步锁和Lock锁只能保证单个实例上的数据一致性,多实例就失去了作用。

这个时候就需要使用分布式锁来保证共享资源的原子性,比如我们电商系统里面的扣减库存,当单量小的时候问题不大,如果单量很大,同一时间多个实例都在并发处理扣减库存的业务的时候,就可能存在超卖的问题。

分布式锁的实现?

常见的分布式锁有数据库实现分布式锁、Zookeeper实现分布式锁、Redis实现分布式锁、Redisson实现。其中数据库实现分布式锁比较简单,也很容易理解,直接基于数据库实现就可以了,在一些分布式的业务中也经常使用,但是这种方式也是效率最低的,一般是不使用的,我们就着重介绍一下其他三种方式的实现。

Zookeeper实现分布式锁

使用Zookeeper来实现分布式锁就比较常见,比如很多项目就使用Zookeeper作为分布式注册中心,就喜欢用Zookeeper来实现分布式锁,这主要是借助于Zookeeper的两大特性:顺序临时节点、Watch机制。

顺序临时节点:熟悉Zookeeper的同学都知道,Zookeeper提供了多层级的节点命名空间,每个节点都是用斜杠分隔的路径来表示,类似于我们的文件夹。节点又分为持久节点和临时节点,节点还可以标记为有序,当节点被标记为有序性,这个节点就具有顺序自增的特点,我们就可以借助这个特点来创建我们所需的节点。

Watch机制:Watch机制是Zookeeper另一个重要的特性,我们可以在指定节点上注册一些Watcher,在一些特定的事情触发的时候,通知用户这个事件。

Zookeeper实现分布式锁的过程

我们先创建一个持久节点作为父节点,每当需要访问创建分布式锁的时候,就在这个父节点下创建相应的临时的顺序子节点,以临时节点名称、父节点名称和顺序号组成特点的名称。在建立子节点后,对父节点下以这个这个子节点名称开头的子节点进行排序,判断刚建立的节点顺序号是不是最小的,如果是最小的则获取锁,如果不是最小节点,则阻塞等待锁,并且在获取该节点的上一顺序节点注册Watcher,等待节点对应的操作获得锁。

当业务处理完之后,删除该节点,关闭zk,进而触发Watcher,释放该锁。

上图就是就是严格按照顺序访问的分布式锁实现,更多的时候我们引入一些框架来帮助我们实现,比如最常用的Curator框架,代码如下:

  1. InterProcessMutex lock = new InterProcessMutex(client, lockPath); 
  2. if ( lock.acquire(maxWait, waitUnit) ) { 
  3.     try { 
  4.         // 业务处理 
  5.     } 
  6.     finally{ 
  7.         lock.release(); 
  8.     } 

Zookeeper来实现分布式锁天然的优势就是,Zookeeper是集群实现的,我们生产环境一般也是集群部署的,可以避免单点问题,稳定性较好,能保证每次操作都可以释放锁。

缺点就是,频繁的创建删除节点,加上注册watch事件,对于zookeeper集群的压力比较大,性能这一块也比不上Redis实现的分布式锁。

Redis实现分布式锁

Redis实现的分布式锁,最为复杂,但是性能确是最佳的,所以在对性能要求更高的系统里,我们都选择使用Redis来实现分布式锁。利用Redis实现分布式锁,一般都是使用SETNX实现,举个简单的例子:

  1. public static boolean getDistributedLock(Jedis jedis, String lockKey, String requestId, int expireTime) { 
  2.  
  3.     String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime); 
  4.  
  5.     if ("OK".equals(result)) { 
  6.          return true
  7.     } 
  8.     return false

SETNX方法保证设置锁和锁过期时间的原子性,但是对于锁的过期时间设置我们要注意,如果执行业务

时间比较长,我们设置的过期时间又比较短的情况下就会造成,业务还没执行完,锁已释放的问题。所以我们需要根据实际业务处理来评估设置锁的过期时间,来保证业务可以正常的处理完。

Redisson实现分布式锁

Redisson是架设在Redis基础上的一个Java驻内存数据网格。Redisson在基于NIO的Netty框架上,充分的利用了Redis键值数据库提供的一系列优势,在Java实用工具包中常用接口的基础上,为使用者提供了一系列具有分布式特性的常用工具类。性能也比我们常用的jedis好一些。

Redisson不管是单节点模式还是集群模式,都很好的实现了分布式锁,一般用的多的都是集群模式,在集群模式下,Redisson使用RedLock算法,很好的处理了Master节点宕机时切换到另外一个Master节点过程中多个应用获得锁。

Redisson集群模式获取锁的实现就是,在不同节点上获取锁,每个节点上获取锁都有超时时间,如果获取锁超时就认为这个节点不可用,当成功获取锁的个数超过Redis节点的半数,且获取锁消耗的时间还没超过锁过期时间,则认为获取锁成功。获取锁成功后重新计算锁释放时间,由原来的锁释放时间减去获取锁消耗的时间,如果最终获取锁失败,已经获取锁成功的节点也会释放锁。

具体的代码实现:

引入依赖

  1. <dependency> 
  2.     <groupId>org.redisson</groupId> 
  3.     <artifactId>redisson</artifactId> 
  4.     <version>3.13.1</version> 
  5. </dependency> 

Redisson配置文件:

  1. @Bean 
  2. public RedissonClient redissonClient() { 
  3.     Config config = new Config(); 
  4.     config.useClusterServers() 
  5.             .setScanInterval(3000) // 集群状态扫描间隔时间,单位是毫秒 
  6.             .addNodeAddress("redis://192.168.0.1:6379).setPassword("666") 
  7.             .addNodeAddress("redis://192.168.0.2:6379").setPassword("666"
  8.             .addNodeAddress("redis://192.168.0.3:6379"
  9.             .setPassword("666"); 
  10.     return Redisson.create(config); 

获取锁操作:

  1. long waitTimeout = 10; 
  2. long leaseTime = 1; 
  3. RLock lock1 = redissonClient1.getLock("lock1"); 
  4. RLock lock2 = redissonClient2.getLock("lock2"); 
  5. RLock lock3 = redissonClient3.getLock("lock3"); 
  6.  
  7. RedissonRedLock redLock = new RedissonRedLock(lock1, lock2, lock3); 
  8.  
  9. redLock.trylock(waitTimeout,leaseTime,TimeUnit.SECONDS); 
  10. try{ 
  11.     //... 
  12. }finally{ 
  13.     redLock.unlock(); 

总结

实现分布式锁的方式不止这三种,最简单的就是数据库实现,Zookeeper实现也相对比较简单,但是性能最好的还是Redis实现,但是可靠性方面,Zookeeper基于分布式集群,具有天然的优势,可靠性相对更高。如果业务场景对性能要求不是很高的时候,优先使用Zookeeper实现分布式锁。

 

文章来源网络,作者:管理,如若转载,请注明出处:https://shuyeidc.com/wp/257841.html<

(0)
管理的头像管理
上一篇2025-05-01 23:13
下一篇 2025-05-01 23:14

相关推荐

  • 站群服务器和普通服务器到底哪个更适合GEO,怎么选?

    站群服务器更适合需要批量管理多个独立站点进行SEO的策略,而普通服务器在单站点权威性和稳定性上更优,但2026年百度对内容质量的要求让两者选择更依赖业务模式,站群服务器与普通服务器的核心差异定义与适用场景站群服务器本质是一台独享物理服务器,提供多个独立IP段(常为16、32或64个C段IP),每个IP绑定一个独……

    2026-07-28
    0
  • 物理服务器和云服务器做站群到底选哪个,哪个更稳定?

    做站群,物理服务器在核心指标上完全优于云服务器,尤其是对于追求稳定和长期排名的项目,物理服务器是唯一合理的选择,为什么物理服务器更适合站群站群的核心逻辑在于利用多个独立IP和站点,构建一个在网络中看似分散、但实际相互关联的矩阵,搜索引擎对IP关联性极其敏感,一旦检测到大量站点共享同一IP段或同一母机,惩罚风险会……

    2026-07-28
    0
  • 国内高防服务器哪家防御真实靠谱,怎么选?

    国内高防服务器哪家防御真实靠谱?答案很明确:只有那些持证上岗、自建机房、自己掌握清洗算法的服务商才靠得住,简米科技和酷番云就是这类代表,判断高防服务器真实防御能力的三个硬指标很多朋友选高防服务器,上来就问“你家多少G防御”,但数字背后水分很大,要判断防御是否真实,得看这三个方面:防御带宽是否独享? 有些服务商宣……

    2026-07-28
    0
  • 裸金属服务器和物理服务器有什么区别?,怎么选?

    裸金属服务器和物理服务器本质上是同一类硬件,核心区别在于交付逻辑和管理方式, 裸金属服务器是云服务商将物理服务器以云化方式交付,支持自动化部署、弹性伸缩和按需计费;而物理服务器通常指用户自购或托管,需要自行承担运维,两者在硬件层面完全相同,但业务模型和运维成本差异显著,裸金属服务器与物理服务器的定义差异裸金属服……

    2026-07-28
    0
  • 做GEO站群选哪家服务器服务商靠谱,怎么选?

    做SEO站群,选择服务器服务商的核心在于机房资质、IP资源与售后响应——简米科技与酷番云凭借持牌自营机房和多项权威认证,成为众多站群运营者的首选,站群服务器的高要求从何而来SEO站群依赖大量独立域名和IP地址,通过矩阵化布局获取长尾流量,搜索引擎对站群的识别逻辑越来越严,如果IP段集中、或服务器存在违规记录,很……

    2026-07-28
    0

发表回复

您的邮箱地址不会被公开。必填项已用 * 标注