Redis 分布式锁

11 篇文章 0 订阅
什么是分布式锁

在每一个 JVM 中都有一个锁监视器,单一个 JVM 中,这个锁监视器可以控制在这个 JVM 中的每个线程,可以实现线程之间的互斥,但是在有多个 JVM 的场景之下,就会有多个锁监视器,这样就无法实现多 JVM 之间的互斥,于是就诞生了分布式锁

分布式锁必须达到的几个条件

分布式锁的实现
MySqlRedisZookeeper
互斥利用 mysql 本身的互斥锁机制利用 setnx 这样的互斥命令利用节点的唯一性和有序性实现互斥
高可用
高性能一般一般
安全性断开连接,自动释放锁利用锁超时时间,到期释放临时节点,断开连接自动释放

实现分布式锁时需要实现的i两个基本方法

  • 获取锁

    • 互斥,确保只能有一个线程获取锁 SETNX lock thread1

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

  • 释放锁

    • 手动释放,DEL lock

    • 超时释放,获取锁时添加一个超时时间 EXPIRE lock 5 , 可以通过 ttl lock 查看还剩多少过期时间

  • 特殊情况

  • 在我执行了获取锁之后还没来得及设置过期时间,服务就宕机了,针对这种情况 SETNX lock EX 5 NX

流程

分布式锁的原子性问题
误删

结合上面的执行逻辑,假如在线程释放锁的时候出现了 JVM 垃圾回收机制导致了线程阻塞,这个时候就很可能会触发锁的超时自动释放

锁一旦超时释放,那么其他的线程就很可能就会乘虚而入,因为没有锁的原因,线程2也会执行他的业务逻辑,就会创建新的锁,这个时候等线程1的阻塞结束之后,线程1并不认识此时的锁已经不是他的了,这个时候就他再来释放锁就会出现误删的情况

当锁再次被删掉之后,如果这个时候还有个线程3的话,那么又会重复执行线程2的操作,又会创建新的锁,那么当线程2执行结束之后又会去删除线程3的锁,循环往复,这就是一个很严重的问题

导致这个问题的情况就是,在判断锁标识和释放锁之间是产生了阻塞最后出现了问题,为了解决这个问题,那么我们就要确保这两个动作必须是一个原子性的操作一起执行,不能出现间隔

解决方法 (Lua)

Redis 提供了 Lua 脚本功能,在一个脚本中编写多条 Redis 命令,确保多条命令执行时的原子性。Lua 是一种编程语言,他的基础语法可以参考 Lua 教程 | 菜鸟教程 和 shell 的语法很类似,对于运维学习起来应该是比较友好的

Redisson
Redisson 背景

基于 setnx 实现的分布式锁存在下面的问题

  • 不可重入,一个线程无法同时获取同一把锁

  • 不可重试,获取锁只尝试一次就返回 false , 没有重试机制

  • 超时释放,锁超时释放虽然可以避免死锁,但如果是业务执行耗时较长,也会导致锁释放,存在安全隐患

  • 主从一致,如果 Redis 提供了主从集群,主从同步存在延迟,当主宕机时,如果从并同步主中的锁数据,则会出现锁实现

Redisson 介绍

Redisson 是一个在 Redis 的基础上实现的 Java 驻内存数据网格 (In-Memory Data Grid). 它不仅提供了一系列的分布式的 Java 常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现

  • 分布式锁(Lock)和同步器(Synchronizer)

  • 可重入锁(Reentrant Lock)

  • 公平锁 (Fair Lock)

  • 联锁 (MultiLock)

  • 红锁 (RedLock)

  • 读写锁 (ReadWriteLock)

  • 信号量 (Semaphore)

  • 可过期性信号量 (PermitExpirableSemaphore)

  • 闭锁 (CountDownLatch)

官网地址 : https://redisson.org

GitHub 地址 : https://github.com/redisson/redisson

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值