我的编程空间,编程开发者的网络收藏夹
学习永远不晚

面试官:项目中如何实现分布式锁?

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

面试官:项目中如何实现分布式锁?

分布式锁(Distributed Lock)是一种用于分布式系统中的同步机制,主要是为了防止分布式系统中,多个服务实例同时操作一个共享资源所带来的并发安全问题。

分布式锁确保在同一时间只有一个实例操作共享资源,从而保证了数据的安全性。

1.分布式锁实现方案

分布式锁的实现方案有多种,例如以下这几种:

  • 基于数据库实现分布式锁:可以通过数据库的乐观锁或悲观锁实现分布式锁,但是由于数据库的 IO 操作比较慢,不适合高并发场景。
  • 基于 Zookeeper 实现分布式锁:Zookeeper 是一个高可用性的分布式协调服务,可以通过它来实现分布式锁。但是使用 Zookeeper 需要部署额外的服务,增加了系统复杂度。
  • 基于 Redis 实现分布式锁:Redis 是一个高性能的内存数据库,支持分布式部署,可以通过 Redis 的原子操作实现分布式锁,而且具有高性能和高可用性。

综合以上方案来看,基于数据库实现的分布式锁不适用于高并发场景,而基于 Zookeeper 实现的分布式锁又需要额外部署 Zookeeper 服务,增加了运营成本,所以使用 Redis 实现分布式锁是目前主流的实现方案。

2.为什么Redis可以实现分布式锁?

因为 Redis 作为一个独立的第三方系统(数据中间件),其本身就支持分布式应用。也就是针对于 Redis 的所有操作,所有的分布式系统都是全局可见的,如下图所示:

3.Redis如何实现分布式锁?

使用 Redis 实现分布式锁的方案有以下 4 种:

  • setnx(set if Not eXists):尝试设置键 key 的值为 value,但如果 key 已经存在,则不会执行任何操作并返回 0,如果 key 不存在则加锁成功。
  • 缺陷:存在死锁问题、锁误删问题、不可重入问题、锁无法自动续期问题。
  • set nx ex/px:setnx 升级版本,Redis 2.6 版本后才能支持此语法。尝试加锁和设置锁超时时间,使用案例 set key value nx px 3000。
  • 缺陷:存在锁误删问题、不可重入问题、锁无法自动续期问题。
  • Lua 脚本:解决锁重入的问题
  • 缺陷:实现复杂、且存在锁无法自动续期问题。
  • Redisson 框架:基于 Redis 实现分布式锁的开源框架。其实现简单、不存在锁重入和锁续期等问题。

问题解释

  • 死锁问题:SETNX 如未设置过期时间,锁忘记删了或加锁线程宕机都会导致死锁,也就是分布式锁一直被占用的情况。
  • 锁误删问题:SETNX 设置了超时时间,但因为执行时间太长,所以在超时时间之内锁已经被自动释放了,但线程不知道,因此在线程执行结束之后,会把其他线程的锁误删的问题。
  • 不可重入问题:也就是说同一线程在已经获取了某个锁的情况下,如果再次请求获取该锁,则请求会失败(因为只有在第一次能加锁成功)。也就是说,一个线程不能对自己已持有的锁进行重复锁定。
  • 无法自动续期:线程在持有锁期间,任务未能执行完成,锁可能会因为超时而自动释放。SETNX 无法自动根据任务的执行情况,设置新的超时实现,以延长锁的时间。

综合以上实现方案来看,生产级别使用 Redis 实现分布式锁的方案,应该选用 Redisson 框架。

4.Redisson介绍

Redisson 是一个开源的用于操作 Redis 的 Java 框架。与 Jedis 和 Lettuce 等轻量级的 Redis 框架不同,它提供了更高级且功能丰富的 Redis 客户端。它提供了许多简化 Redis 操作的高级 API,并支持分布式对象、分布式锁、分布式集合等特性。

Redisson 官网:https://redisson.org/

Redisson 特性说明

  • Redisson 可以设置分布式锁的过期时间,从而避免锁一直被占用而导致的死锁问题。
  • Redisson 在为每个锁关联一个线程 ID 和重入次数(递增计数器)作为分布锁 value 的一部分存储在 Redis 中,这样就避免了锁误删和不可重入的问题。
  • Redisson 还提供了自动续期的功能,通过定时任务(看门狗)定期延长锁的有效期,确保在业务未完成前,锁不会被其他线程获取。

5.Redisson实现分布式锁

(1)添加 Redisson 框架

添加 Redisson 依赖:




  org.redisson
  redisson-spring-boot-starter

(2)配置 Redis 连接信息

将 RedissonClient 对象保存到 Spring Ioc 容器,并为其设置 Redis 服务连接信息,具体实现代码如下:

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
    @Bean
    public RedissonClient redissonClient() {
        Config config = new Config();
        // 也可以将 redis 配置信息保存到配置文件
        config.useSingleServer().setAddress("redis://127.0.0.1:6379");
        return Redisson.create(config);
    }
}

(3)创建分布式锁

Redisson 分布式锁的操作和 Java 中的 ReentrantLock(可重入锁)的操作很像,都是先使用 tryLock 尝试获取(非公平)锁,再通过 unlock 释放锁,具体实现如下:

import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit;
@RestController
public class LockController {
    @Autowired
    private RedissonClient redissonClient;
    @GetMapping("/lock")
    public String lockResource() throws InterruptedException {
        String lockKey = "myLock";
        // 获取 RLock 对象
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁(尝试加锁)(锁超时时间是 30 秒)
            boolean isLocked = lock.tryLock(30, TimeUnit.SECONDS);
            if (isLocked) {
                // 成功获取到锁
                try {
                    // 模拟业务处理
                    TimeUnit.SECONDS.sleep(5);
                    return "成功获取锁,并执行业务代码";
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // 释放锁
                    lock.unlock();
                }
            } else {
                // 获取锁失败
                return "获取锁失败";
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "获取锁成功";
    }
}

a.实现公平锁

Redisson 默认创建的分布式锁是非公平锁(出于性能的考虑),想要把它变成公平锁可使用以下代码实现:

RLock lock = redissonClient.getFairLock(lockKey);  // 获取公平锁

b.实现读写锁

Redisson 还可以创建读写锁,如下代码所示:

RReadWriteLock lock = redissonClient.getReadWriteLock(lockKey); // 获取读写锁
lock.readLock();  // 读锁
lock.writeLock(); // 写锁

读写锁的特点就是并发性能高,它是允许多个线程同时获取读锁进行读操作的,也就是说在没有写锁的情况下,读取操作可以并发执行,提高了系统的并行度。但写锁则是独占式的,同一时间只有一个线程可以获得写锁,无论是读还是写都无法与写锁并存,这样就确保了数据修改时的数据一致性。

c.实现联锁

Redisson 也支持联锁,也叫分布式多锁 MultiLock,它允许客户端一次性获取多个独立资源(RLock)上的锁,这些资源可能是不同的键或同一键的不同锁。当所有指定的锁都被成功获取后,才会认为整个操作成功锁定。这样能够确保在分布式环境下进行跨资源的并发控制。

联锁的实现示例如下:

// 获取需要加锁的资源
RLock lock1 = redisson.getLock("lock1");
RLock lock2 = redisson.getLock("lock2");
// 联锁
RedissonMultiLock multiLock = new RedissonMultiLock(lock1, lock2);
try {
    // 一次性尝试获取所有锁
    if (multiLock.tryLock()) {
        // 获取锁成功...
    }
} finally {
    // 释放所有锁
    multiLock.unlock();
}

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

面试官:项目中如何实现分布式锁?

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

面试官:项目中如何实现分布式锁?

分布式锁(Distributed Lock)是一种用于分布式系统中的同步机制,主要是为了防止分布式系统中,多个服务实例同时操作一个共享资源所带来的并发安全问题。

面试官:如何用 Redis 实现分布式锁?

Redis 本身可以被多个客户端共享访问,正好就是一个共享存储系统,可以用来保存分布式锁,而且 Redis 的读写性能高,可以应对高并发的锁操作场景。

面试官:项目中如何实现布隆过滤器?

对于布隆过滤器是什么?以及布隆过滤器的实现原理?相信大部分同学都能回答个七七八八。当如果被问道:项目当中是如何实现布隆过滤器的?这个时候大部分同学就又回答不上来了,所以今天咱们就来探讨一下这个问题。

【大厂面试题】Redis中是如何实现分布式锁的?

你对Redis使用熟悉吗?Redis中是如何实现分布式锁的。下面让我们来看一下吧。

面试官问用Zookeeper怎么实现分布式锁,你知道吗???

因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。大家知道,ZK中创建和删除节点只能通过Leader​服务器来执行,然后Leader服务器还需要将数据同不到所有的Follower机器上,这样频繁的网络通信,性能的短板

Redis中如何实现分布式锁

这篇文章给大家介绍Redis中如何实现分布式锁,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Redis要实现分布式锁,以下条件应该得到满足互斥性 在任意时刻,只有一个客户端能持有锁。不能死锁 客户端在持有锁的期间崩溃而
2023-06-16

面试官:如何实现文件的大规模分布式存储?

在生产环境中,往往需要对FastDFS实现高可用,进而实现文件的大规模分布式存储。那么,如何实现FastDFS的高可用呢?今天,我们就基于CentOS 8服务器来搭建FastDFS高可用集群环境。

如何在Redis中实现分布式锁

在Redis中实现分布式锁可以通过以下方式:使用SETNX命令:在Redis中可以使用SETNX命令(SET if Not eXists)来设置一个键值对,只有在键不存在的情况下才会执行设置操作。通过SETNX命令可以尝试在指定的键上设置一
如何在Redis中实现分布式锁
2024-04-09

Redis 如何实现分布式锁?

Redis 作为一个独立的三方系统,其优势是天生可以实现分布式锁。它实现分布式锁是通过 setnx 来实现的,然而只有 nx(not exists)可能会发生死锁的问题,所以我们最终实现死锁应该使用 set nx ex 的方式来实现。

zookeeper分布式锁如何实现

这篇文章主要介绍“zookeeper分布式锁如何实现”,在日常操作中,相信很多人在zookeeper分布式锁如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”zookeeper分布式锁如何实现”的疑惑有所
2023-06-27

Java分布式锁如何实现

这篇“Java分布式锁如何实现”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java分布式锁如何实现”文章吧。一、分布式锁介
2023-07-05

Zookeeper如何实现分布式锁

这篇“Zookeeper如何实现分布式锁”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Zookeeper如何实现分布式锁”文
2023-06-27

Redisson如何实现分布式锁、锁续约

这篇文章主要介绍了Redisson如何实现分布式锁、锁续约的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Redisson如何实现分布式锁、锁续约文章都会有所收获,下面我们一起来看看吧。一、基础0)Redisso
2023-07-05

在Spring项目中实现分布式session

在Spring项目中实现分布式session?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。1. 引入Spring Session maven依赖