Redis实现分布式锁

发布时间:2024年01月03日

1. 为什么需要分布式锁??

我们都知道,Java提供的synchronized / lock锁只能作用在单个JVM中的单个应用中,Java中的锁只能锁定JVM级别的锁:

  • synchronized就是利用JVM内部的锁监视器来控制线程的,在JVM的内部,因为只有一个锁监视器,所以只能有一个线程获取到锁,实现线程间的互斥;但是当有多个JVM的时候,就会有多个锁监视器,此时就会有多个线程获取到锁,这个时候就没有办法实现多JVM进程之间的互斥了。

而如果在以下场景下,比如:

  • 单个应用进行集群部署,负载均衡可能把请求分配到不同的机器上
  • 多个不同的分布式应用,多个应用需要同时锁定同一个资源

以上情况,单机锁就会失效,此时就需要一种全局应用锁代替单机锁,即:分布式锁。?

2. 单机锁 & 分布式锁的定义:?

  • 单机锁:在单个JVM进程内起作用的同步机制,用于控制对共享资源的访问,这种锁,主要适用于单体应用,用于控制在同一JVM进程中多个线程对共享资源的互斥访问。
  • 分布式锁:满足分布式系统或集群模式下多进程可见并且互斥的锁,分布式锁用于协调分布式系统中的不同节点,以确保在全局范围内对共享资源的互斥访问。

锁的本质:让程序并行执行变成串行执行~!

3. 分布式锁应该具备哪些条件?

  • 多线程可见
  • 互斥
  • 可重入:同一个线程可以反复获取锁,避免死锁
  • 具备非阻塞锁特性:获取锁失败立即返回
  • 获取锁和释放锁要具备高可用、高性能?

4. 分布式锁都有哪些主流的实现方案?

分布式锁的核心是实现多线程之间互斥,而满足这一点的方式有很多,常见的有三种:?

  • Redis:简单,速度快,性能最好,现在企业级开发基本都使用Redis或者Zookeeper作为分布式锁,简单的SET NX EX这样的互斥命令就可以实现,如果插入key成功,则表示获取到了锁,如果插入失败则表示获取锁失败,而且还可以自动过期,利用锁超时时间自动释放,防止忘记释放锁
  • MySQL:MySQL本身就带有锁机制(select...from...where..for update => 这是一种悲观锁,会锁住对应的索引行),利用MySQL本身的互斥锁机制来实现分布式锁,不用引入新的中间件,而是作为传统关系型数据库,存储的锁信息更详细,断开连接时自动释放锁,但是由于MySQL性能本身一般(锁的性能受限于MySQL的性能),所以使用MySQL作为分布式锁比较少见
  • Zookeeper:Zookeeper也是企业级开发中较好的一个实现分布式锁的方案,利用临时顺序节点实现互斥锁利用节点的唯一性和有序性实现互斥,断开连接时自动释放锁,更稳定更可靠,它不依靠超时时间释放锁,可靠性比Redis更高,同时也更复杂

5. 如何用 Redis 实现分布式锁的??

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

Redis的SET命令有个NX参数可以实现「key不存在才插入」,所以可以用它来实现分布式锁:?

  • 如果key不存在,则显示插入成功,可以用来表示加锁成功;
  • 如果key存在,则会显示插入失败,可以用来表示加锁失败。?

del或UNLINK删除key代表释放锁?

另外,我们可以在SET命令执行时加上 EX / PX 选项,设置过期时间以免客户端拿到锁后发生异常,导致锁一直无法释放。?

实现分布式锁时需要实现的两个基本方法:
  • 获取锁:

    • 互斥:确保只能有一个线程获取到锁? =>? 添加锁,利用setnx的互斥特性

    • 非阻塞:尝试一次,成功则返回true,失败则返回false

  • 释放锁:

    • 手动释放:DEL手动删除

    • 超时释放:获取锁时添加一个超时时间

?

?

文章来源:https://blog.csdn.net/weixin_53622554/article/details/135371011
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。