Redis机制-Redis互斥锁、分布式锁

目录

[一 互斥锁](#一 互斥锁)

[二 分布式锁](#二 分布式锁)

Redis实现分布式锁

redisson实现分布式锁

可重入性:

主从一致性(性能差):


一 互斥锁

假设我们现在有一个业务要实现秒杀优惠券的功能,如果是一个正常的流程,线程之间应该是这样运作的。

线程1先查询优惠券,如果库存充足,那么扣减库存,然后线程2来查询优惠券信息,如果充足,那么就扣减库存,但是这只是理想的情况。

那么如果出现图2的这种情况呢?

线程1在查询优惠券信息的时候发现库存是充足的,线程2查询的时候也是充足的,他俩都可以进行减库存的操作,假如优惠券只剩1张了,那么谁得到这个优惠券呢?这就是业务中可能出现的问题。

此时就需要用互斥锁来解决问题了

如图,假如线程1在获取互斥锁以后,线程2来了之后就只能发起获取锁的请求,只有当线程1操作完了之后释放锁,线程2获取到锁,才可以进行接下来的操作,这样就不会出现库存超卖的情况。

但是还有一个问题,上面所说的这种情况是针对单个Redis服务器进行加锁的,但是实际的业务逻辑中可能会有多个用户,访问多个Redis服务器,那么这时候要怎么解决呢?

二 分布式锁

假设我的代码部署到了多个tomcat中,每一个tomcat操控一个JVM,此时8080的虚拟机知道8081的线程1也在同时访问优惠券信息吗?这显然是不知道的。

此时就需要用到一个独立于tomcat之外的分布式锁来进行判断

如图,当8080的线程1进行访问时,其余的端口和线程都不可以进行访问,此时就达到了分布式锁的效果,有效的解决了超卖问题。要注意,分布式锁是加在Redis上的,不是自己的代码中。

Redis实现分布式锁

Redis实现分布式锁主要是利用Redis的setnx命令

java 复制代码
SET LOCK VALUE NX EX 10  //加锁
DEL key                  //释放锁

第一条代码是加锁并且给锁设置过期时间,第二行代码是删除锁。如果不给锁设置过期时间,那么就有可能产生死锁的现象。即线程1执行时间过长,线程2一直在等待锁释放。

redisson实现分布式锁

redisson中也有分布式锁的实现

java 复制代码
RLock lock = redissonClient.getLock("lock");
try{
    boolean isLock = lock.tryLock(10,TimeUnit.SECONDS);
    if(isLock){
        System.out.println("执行业务");
    }
} finally{
    lock.unlock();
  }

首先,线程1获取到锁之后,然后去操作Redis,也会去通知看门狗系统,而看门狗系统会每隔释放时间(redisson默认30秒)/3去给锁续期,希望业务完成之前不要因为锁到期而引发线程安全问题,此时线程1执行完,线程2获取到锁就可以继续执行了。而加锁和设置过期时间都是基于lua脚本完成的,这样可以保证操作的原子性。

可重入性:

假设下图是线程1所执行的代码,在redis当中会按照哈希结构去进行存储,key为锁的key,value会存储一个键值对,键为线程名称,value为锁的次数默认为0,加一次锁就+1,释放一次锁就-1.

|---------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------|
| | |

如上图,执行add1( )时,Thread1第一次加锁时,value会被改成1,当add2( )想获取锁时,此时Redis会进行判断,你是不是线程1来的,发现add2( )的线程名为Thread1,那么此时该锁可以重入的,value值会变成2,当add2( )执行完以后,释放锁,value又变为1,add1( )执行完以后,value变成0,此时的锁才是真正被线程1所释放了。

主从一致性(性能差):

如图,如果是在集群模式下的Redis服务器势必会有主节点和从节点,当线程1过来获取到一把锁时,主节点刚好宕机了,集群又重新选了一个主节点,线程2此时又获取到了和线程1同样的一把锁,这样就会产生锁冲突的现象。

针对这样的情况就要加红锁(RedLock):在多个Redis实例上加锁,而不是只在一个节点上进行加锁,这样就可以避免锁重复。

但是这样实现相对来说比较复杂,因此AP思想和CP思想(zookeeper)可以解决该问题。

所以说性能和复杂是负相关的。

相关推荐
极客先躯7 分钟前
Hadoop krb5.conf 配置详解
大数据·hadoop·分布式·kerberos·krb5.conf·认证系统
CopyLower1 小时前
Kafka 消费者状态及高水位(High Watermark)详解
分布式·kafka
Java探秘者2 小时前
Maven下载、安装与环境配置详解:从零开始搭建高效Java开发环境
java·开发语言·数据库·spring boot·spring cloud·maven·idea
2301_786964363 小时前
3、练习常用的HBase Shell命令+HBase 常用的Java API 及应用实例
java·大数据·数据库·分布式·hbase
千年死缓3 小时前
go+redis基于tcp实现聊天室
redis·tcp/ip·golang
阿维的博客日记3 小时前
图文并茂解释水平分表,垂直分表,水平分库,垂直分库
数据库·分库分表
信徒_4 小时前
kafka
分布式·kafka
Uranus^4 小时前
rabbitMQ 简单使用
分布式·rabbitmq
攒了一袋星辰4 小时前
今日指数项目项目集成RabbitMQ与CaffienCatch
java·分布式·rabbitmq
wrx繁星点点4 小时前
事务的四大特性(ACID)
java·开发语言·数据库