Redis分布式锁零散知识

本文探讨了Redis分布式锁的四个关键条件,包括互斥性、防止死锁、容错性和客户端锁定。对比了Redis分布式锁与Java锁的差异,指出Redis锁在分布式环境中的优势与限制。此外,分析了Redis与Zookeeper作为分布式锁的选择,并提到了Redisson和RedLock两种实现方式的潜在问题。最后,概述了分布式锁的加锁策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、为了确保分布式锁的可用性,需要确保锁在任意时刻,能同时满足以下四个条件
1.互斥性:在任意时刻,只有一个客户端能持有锁
2.不会发送死锁,即时有一个客户端在持有锁期间崩溃而没有主动解锁,也需要保证其他客户端能加锁
3.具有容错性,只要大部分的Redis节点正常运行,客户端就可以加锁解锁
4.加锁和解锁必须是同一个客户端

二、Redis分布式锁和Java锁的区别
1. 如果是分布式部署的话,那么Java锁是锁当前机器上的请求,无法对其他机器的请求进行加锁,因为Java锁用的是jvm的机制,只在本机生效
2. 姑且说项目就是单机部署的,那么在加锁的时候,Java锁的粒度会更大,Java锁会对接口的其他请求全部阻塞,但是分布式锁,只会对接口的某一个key进行请求的时候,加锁;因为Redis分布式锁有key的入参,如果同时key1和key2都来请求接口,那么Redis分布式锁可以同时执行,但是Java锁,不行,会阻塞key2的请求

三、Redis分布式锁和zk分布式锁怎么选择:
1.Redis采用的是AP模式,zk采用的是CP模式
2.Redis分布式锁简单粗暴,获取不到锁,就直接不断的重试,比较消费资源、性能
3.Redis本身的设计就不是强一致性的,所以,在一些极端的场景下,会出现问题,但是大部分情况下,是不会遇到所谓的极端复杂场景,所以,使用Redis锁也是一个选择
4.zk的设计就是强一致性,如果获取不到锁,就添加一个监听,不用一直轮询,但是zk也有其缺点,如果有较多的客户端频繁的申请加锁解锁,对zk集群的压力比较大

Redis是典型的AP模型,也就是保证高可用,和数据的最终一致性,基于这个模型,在使用Redis分布式锁的时候,就有可能会出现问题

redisson分布式锁:
1.线程A加锁,加锁成功,然后master节点将数据同步到slave,在同步的时候,出现异常,导致master宕机,但是数据也没有同步到slave
2.此时slave升级为master,那此时的话,线程B继续对同一个key加锁,会加锁成功,因为此时的master,没有这把锁记录

redLock:
要求多个节点独立部署,在加锁的时候,会依次去多个节点上加锁,只要有半数以上的节点,加锁成功,就会认为当前线程加锁成功,那基于这个前提,我们实际举例
1.当前是三台机器集群部署,线程A加锁,加入此时对1、2、3三台机器加锁成功,
2.线程B也过来加锁,对3、4、5机器进行加锁,但是3这台机器会加锁失败
3.假如出现极端场景,线程A在释放锁的时候,先释放了3这台机器,然后在去释放1和2的时候,由于网络或者其他原因,导致线程暂停,此时线程B会加锁成功
4.线程B加锁成功之后,会去持有锁,执行自己的业务逻辑,但是在线程A唤醒的一瞬间,当前三台Redis机器上,会同时有两个线程同时持有同一把锁

四、分布式锁加锁思路

1.进入方法之后,首先查询缓存,如果缓存命中,return
2.如果缓存未命中,则查询数据库,但是在查询数据库之前,进行加锁
3.加锁之后,再查询一遍缓存,这里查询缓存,是为了防止第二个阻塞在加锁这里的线程,在获取到锁之后,直接查询数据库
4.如果缓存命中,就返回,如果未命中,查询数据库,并放入到缓存中
5.最后释放锁


String value = redisTemplate.get(key);
if(value != null){
    return value;
}
redisson.lock();
try{
  /**
  * 这里加锁之后,还是再次查询Redis,防止这种场景:
  * A和B连个线程同时执行该方法,A线程获取到锁,B线程阻塞到redisson.lock()这里;那么A在从数据库中查询到数据之后,会将数据写入Redis,在A释放了锁之后。B获取了执行权限,在B获取执行权限的时候,A已经将数据写入了Redis,此时,B就无需再次查询数据库
  */
  String valueTemp = redisTemplate.get(key);
  if(valueTemp != null){
        return valueTemp;
    }
  OerChannelEntity operChannelEntity = operChannelDao.selectById(key);
  redisTemplate.set(key,operChannelEntity.getName);
  return operChannelEntity.getName;
}finally{
  redisson.unlock();
}
### 分布式内存技术原理 分布式内存是指在网络环境中多个节点共享的虚拟地址空间,允许不同计算机上的应用程序像访问本地资源一样高效地读写远程机器上的数据。这种机制极大地提高了大型集群环境下的数据处理效率响应速度。 #### 技术实现方式 为了使各个节点之间能够有效地协作并保持一致性,通常采用以下几种关键技术: - **消息传递接口(MPI)**:这是一种标准化的消息传递库规范,用于编写并行程序。MPI提供了丰富的函数集来发送接收信息以及同步进程之间的执行流程[^5]。 - **共享内存区**:在某些情况下,可以通过设置特定区域作为全局可见的空间供所有成员共同使用。不过这种方式往往受限于硬件架构的支持程度,并不是所有的分布式系统都适用此方案[^1]。 - **对象网格(Object Grids)** **键值存储(Key-value Stores)** :这两种模式下,开发者可以定义一组服务器组成的网络,在其中保存任意类型的对象或简单映射关系。当客户端请求到来时,负责协调工作的中间件会选择最合适的位置来进行操作[^2]。 #### 应用实例 ##### Spark 的内存管理 Spark 是一个典型的利用分布式内存在大数据领域取得成功的例子。作为一个高效的批处理引擎,它能够在内存中缓存中间结果以减少磁盘 I/O 开销,从而加速迭代式的算法运算过程。具体而言,RDD (Resilient Distributed Dataset) 构成了 Spark 内核的核心抽象层,使得用户可以在不丢失容错性的前提下充分利用集群内的闲置 RAM 资源完成复杂任务。 ```python from pyspark import SparkContext, SparkConf conf = SparkConf().setAppName("example").setMaster("local[*]") sc = SparkContext(conf=conf) data = sc.parallelize([i for i in range(0, 10)]) cached_data = data.persist() # 将 RDD 缓存至内存 result = cached_data.reduce(lambda a, b: a + b) print(result) ``` ##### Redis 的内存分配策略 除了批量数据分析外,实时应用场景同样依赖着强大的分布式内存支撑。例如 NoSQL 数据库 Redis 使用动态申请的方式为每条记录分配必要的字节数量,而不是预先设定固定大小的区块。这样的设计既灵活又节省了宝贵的物理容量,同时也引入了一定比例的小块未使用的零散片段——即所谓的“内存碎片”。尽管如此,对于大多数在线业务来说,Redis 提供的服务质量性能仍然是无可比拟的优势所在[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值