【分布式理论10】分布式协同:分布式互斥算法最佳实现:分布式锁的原理与实现

一、分布式锁的由来和定义

在分布式系统中,多个进程可能会同时访问同一个临界资源,导致数据竞争问题。例如,在秒杀活动中,多个用户同时下单会导致库存扣减的并发冲突。为了解决这一问题,需要引入分布式锁,确保同一时刻只有一个进程能够访问共享资源,从而避免数据不一致问题。

分布式锁的实现方式有多种,包括基于数据库、Redis、ZooKeeper 等方案。其中,数据库实现方式虽然简单,但性能较低,适用于低并发场景。因此,在高并发的应用场景中,通常使用 Redis 和 ZooKeeper 实现分布式锁。

在这里插入图片描述

 

二、用数据库实现分布式锁(不推荐)

用数据库实现分布式锁比较简单,就是创建一张锁表。要锁住临界资源并对其访问时,在锁表中增加一条记录即可;删除某条记录就可释放相应的临界资源。数据库对临界资源做了唯一性约束,如果有访问临界资源的请求同时提交到数据库,数据库会保证只有一个请求能够得到锁,然后只有得到锁的这个请求才可以访问临界资源。

由于此类操作属于数据库 IO 操作,效率不高,而且频繁操作会增大数据库的开销,因此这种方式在高并发、对性能要求较高的场景中使用得并不多。

 

三、 通过 Redis 缓存实现分布式锁

前面提到库存作为临界资源会遭遇高并发的请求访问,为了提高效率,可以将库存信息放到缓存中。以流行的 Redis 为例,用其存放库存信息,当多个进程同时请求访问库存时会出现资源争夺现象,也就是分布式程序争夺唯一资源。为了解决这个问题,需要实现分布式锁。
一个进程持有锁后,就可以访问 Redis 中的库存资源,且在其访问期间其他进程是不能访问的。

如下图:假设有多个扣减服务用于响应用户的下单请求,这些服务接收到请求后会去访问Redis 缓存中存放的库存信息,每接收一次用户请求,就将 Redis 中存放的库存量减去 1。

在这里插入图片描述

 
超时时间的考虑

如果该进程长期没有释放锁,就会造成其他进程饥饿,因此需要考虑锁的过期时间,设置超时时间。

Redis 通过 SETNX(set if not exists)命令和 EXPIRE(设置过期时间)命令可以实现互斥访问。这里的超时时间需要考虑两方面问题。

  • 资源本身的超时时间,一旦资源被使用一段时间后还没有被释放,Redis 就会自动释放该资源,给其他服务使用。
  • 服务访问资源的超时时间,如果一个服务访问资源超过一段时间,那么不管这个服务是否处理完,都要马上释放资源给其他服务使用。

下单服务中的扣减操作属于核心操作,因此会用到第二种方式。如果到达规定时间,下单服务还没有处理完库存资源,就重新申请资源并且延长持有锁的时间

 

代码示例(基于 Redisson 实现 Redis 分布式锁)

这里以 Redisson 为例介绍如何实现分布式锁​。

public void testLock() {
   
   
    Config config = new Config();
    config.useSingleServer()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

roman_日积跬步-终至千里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值