美文网首页
分布式锁实现方案

分布式锁实现方案

作者: code_搬运工 | 来源:发表于2025-08-11 08:46 被阅读0次

一、分布式锁场景

分布式锁主要解决分布式系统中多服务实例共享资源竞争的问题,在单体应用中本地锁(如synchronized、ReentrantLock)可保证线程安全,但分布式环境下(多 JVM、多节点),本地锁无法跨实例生效,此时需要分布式锁。常见场景包括:

  1. 库存扣减:秒杀、促销活动中,多个服务实例同时扣减同一商品库存,需防止超卖;
  2. 分布式任务调度:避免多个节点重复执行同一定时任务(如数据同步、报表生成);
  3. 分布式事务:确保跨服务的原子操作(如转账时 “扣钱” 和 “加钱” 需同时成功或失败);
  4. 缓存更新:防止缓存击穿(多个线程同时请求失效的缓存,导致数据库压力骤增)。

二、分布式锁特点

分布式锁需满足以下核心特性,才能保证在分布式环境下有效工作:

  1. 互斥性:同一时间只能有一个服务实例获取锁,确保共享资源操作的唯一性;
  2. 安全性:避免死锁(如服务崩溃后锁无法释放),需支持自动释放机制;
  3. 高可用:锁服务本身需高可用(避免单点故障),获取 / 释放锁的过程不能成为系统瓶颈;
  4. 可重入性:同一服务实例可多次获取同一把锁(如递归调用场景),避免自己阻塞自己;
  5. 公平性(可选):按请求顺序获取锁,防止 “饥饿”(部分请求长期无法获取锁);
  6. 高性能:获取 / 释放锁的操作需高效(低延迟、高并发支持),减少对业务的影响。

三、分布式锁得实现

在 SpringBoot 中,分布式锁的实现通常依赖中间件,主流方案包括Redis、ZooKeeper、数据库三种,各有优劣:

1. 基于 Redis 的分布式锁

原理:利用 Redis 的SET命令原子性(NX- 不存在则设置,PX- 过期时间)实现锁的获取,通过 Lua 脚本原子性删除实现锁的释放。

获取锁:
执行命令 SET lock_key unique_value NX PX 30000(unique_value为服务实例唯一标识,如 UUID;PX 30000表示 30 秒后自动释放,防止死锁)。
若返回OK,则表示获取锁成功;否则失败。
释放锁:
需先判断锁的unique_value是否为当前实例,再删除(避免误删其他实例的锁),通过 Lua 脚本保证原子性:

if redis.call('get', KEYS[1]) == ARGV[1] then
  return redis.call('del', KEYS[1])
else
  return 0
end

SpringBoot 集成:
推荐使用Redisson客户端,它封装了分布式锁的实现,支持可重入(RLock)、自动续期(看门狗机制)、公平锁等特性,无需手动处理过期时间:


@Autowired
private RedissonClient redissonClient;

public void doWithLock() {
    RLock lock = redissonClient.getLock("stock:lock:1001"); // 锁的key(如商品ID)
    try {
        // 尝试获取锁,最多等待10秒,10秒后自动释放
        boolean locked = lock.tryLock(10, 10, TimeUnit.SECONDS);
        if (locked) {
            // 执行业务逻辑(如扣减库存)
        }
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    } finally {
        // 释放锁(需判断是否持有锁,避免异常场景下误释放)
        if (lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
}

优缺点:
优点:性能极高(Redis 读写快),适合高并发场景;
缺点:需处理锁过期问题(若业务执行时间超过过期时间,可能导致锁提前释放),Redisson 的看门狗机制可缓解此问题

2. 基于 ZooKeeper 的分布式锁

原理:利用 ZooKeeper 的临时有序节点和监听机制实现。每个请求创建一个临时有序节点,若自身是最小节点则获取锁;否则监听前一个节点,前一个节点删除后自动竞争锁。

获取锁:
在/lock节点下创建临时有序节点(如/lock/lock-00000001);
获取/lock下所有子节点,判断自身是否为最小节点:是则获取锁;否则监听前一个节点的删除事件。
释放锁:
服务实例释放锁时,删除自身创建的临时节点;若服务崩溃,ZooKeeper 会自动删除临时节点(会话断开),避免死锁。
SpringBoot 集成:
使用Curator框架(ZooKeeper 客户端),其InterProcessMutex类封装了分布式锁实现:

@Autowired
private CuratorFramework curatorFramework;

public void doWithLock() throws Exception {
    InterProcessMutex lock = new InterProcessMutex(curatorFramework, "/lock/stock/1001");
    try {
        // 尝试获取锁,最多等待10秒
        boolean locked = lock.acquire(10, TimeUnit.SECONDS);
        if (locked) {
            // 执行业务逻辑
        }
    } finally {
        // 释放锁
        if (lock.isAcquiredInThisProcess()) {
            lock.release();
        }
    }
}

优缺点:
优点:可靠性高(天然支持监听和自动释放),适合对一致性要求高的场景;
缺点:性能低于 Redis(需频繁创建 / 删除节点和网络通信),适合并发量中等的场景。

3. 基于数据库的分布式锁

原理:利用数据库的行锁或唯一约束实现,常见两种方式:

悲观锁(行锁):
通过select ... for update获取行锁,其他事务需等待锁释放。例如:

select * from distributed_lock where lock_key = 'stock:1001' for update;

执行后,其他事务对该记录的操作会阻塞,直到当前事务提交 / 回滚释放锁。

乐观锁(版本号):
基于版本号控制,更新时判断版本号是否匹配,不阻塞但可能重试:

update distributed_lock set count = count - 1, version = version + 1 
where lock_key = 'stock:1001' and version = #{currentVersion};

若更新行数为 0,说明版本号已变(被其他事务修改),需重试。
SpringBoot 集成:
通过 MyBatis/JPA 执行上述 SQL,例如用乐观锁

@Update("update distributed_lock set count = count - 1, version = version + 1 where lock_key = #{lockKey} and version = #{version}")
int updateStock(@Param("lockKey") String lockKey, @Param("version") int version);

优缺点:
优点:实现简单(无需额外中间件);
缺点:性能差(悲观锁阻塞,乐观锁可能频繁重试),不适合高并发场景;数据库易成为瓶颈。

总结
实际开发中,需根据场景选择方案:

高并发、高性能优先:选 Redis(Redisson);
高可靠性、一致性优先:选 ZooKeeper(Curator);
简单场景、低并发:可选数据库锁(不推荐高并发)。

在 SpringBoot 中,优先使用成熟客户端(如 Redisson、Curator),避免重复开发锁的细节(如自动续期、异常处理)。

四、

相关文章

  • 基于redis的分布式锁

    分布式锁实现方案 基于数据库实现分布式锁 基于缓存(redis,memcached,tair)实现分布式锁 基于Z...

  • 分布式锁的实现方案

    一,分布式锁的实现方案 1,基于数据库实现分布式锁 2,基于缓存实现数据库锁(redis) 3,基于zookeep...

  • zookeeper 锁

    常见的分布式锁实现方案里面,除了使用redis来实现之外,使用zookeeper也可以实现分布式锁。关于 redi...

  • Redis分布式锁

    Redis之分布式锁的实现方案 - 如何优雅地实现分布式锁(JAVA)博客地址 https://blog.piao...

  • 主流分布式锁实现方案

    谈到分布式系统,就不得不谈谈分布式锁。而主流的实现java分布式锁实现方案也就那么几种,有基于Redis实现的,也...

  • 3、分布式锁

    对于分布式锁可以从几个问题入手: 分布式锁应用的场景是什么样的呢?分布式锁的实现是怎么样的呢?分布式锁的实现方案应...

  • 分布式锁

    为什么要用分布式锁? 分布式锁是悲观锁的实现; 如果采用乐观锁的方案就用不着分布式锁了。 能用乐观锁的地方尽量用乐...

  • 分布式锁

    针对分布式锁的实现,目前比较常用的有以下几种方案: 基于数据库实现分布式锁 基于缓存(redis,memcache...

  • 82zookeeper 分布式锁(二)避免羊群效应

    分布式解决方案: 分布式锁常见问题: 1,Zookeeper如何实现分布式锁; 1,重试策略;2,超时策略;3,续...

  • 基于 Redis 的分布式锁实现

    1. 前言 关于分布式锁的实现,目前常用的方案有以下三类: 数据库乐观锁; 基于分布式缓存实现的锁服务,典型代表有...

网友评论

      本文标题:分布式锁实现方案

      本文链接:https://www.haomeiwen.com/subject/tmhmojtx.html