redis:六、数据过期删除策略(惰性删除、定期删除)和基于redisson实现的分布式锁(看门狗机制、主从一致性)和面试模板

本文主要是介绍redis:六、数据过期删除策略(惰性删除、定期删除)和基于redisson实现的分布式锁(看门狗机制、主从一致性)和面试模板,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数据过期删除策略

Redis的过期删除策略:惰性删除 + 定期删除两种策略进行配合使用

惰性删除

惰性删除:设置该key过期时间后,我们不去管它,当需要该key时,我们在检查其是否过期,如果过期,我们就删掉它,反之返回该key

优点 :对CPU友好,只会在使用该key时才会进行过期检查,对于很多用不到的key不用浪费时间进行过期检查
缺点 :对内存不友好,如果一个key已经过期,但是一直没有使用,那么该key就会一直存在内存中,内存永远不会释放。

定期删除

定期删除:每隔一段时间,我们就对一些key进行检查,删除里面过期的key(从一定数量的数据库中取出一定数量的随机key进行检查,并删除其中的过期key)。

定期清理有两种模式:
SLOW模式是定时任务,执行频率可以通过修改配置文件redis.conf 来调整。
FAST模式执行频率不固定,但两次间隔不低于2ms,每次耗时不超过1ms。

优点:可以通过限制删除操作执行的时长和频率来减少删除操作对 CPU 的影响。另外定期删除,也能有效释放过期键占用的内存。
缺点:难以确定删除操作执行的时长和频率。

面试回答模板

Redis的数据过期策略有哪些 ?

背熟以下答案,大概用时1min。

在redis中提供了两种数据过期删除策略,第一种是惰性删除,在设置该key过期时间后,我们不去管它,当需要该key时,我们再检查其是否过期,如果过期,我们就删掉它,反之返回该key。

第二种是定期删除,就是说每隔一段时间,我们就对一些key进行检查,删除里面过期的key。
定期删除存在两种模式:
SLOW模式是定时任务,任务执行频率可以通过修改配置文件redis.conf 来调整。
FAST模式执行频率不固定,但两次之间的间隔和每次耗时都有固定值。

Redis的过期删除策略实际是惰性删除和定期删除两种策略配合使用的。

分布式锁

Redis实现分布式锁主要利用Redis的setnx命令。setnx是SET if not exists(如果不存在,则 SET)的简写。

获取锁

命令:

# 添加锁,NX是互斥、EX是设置超时时间
SET lock value NX EX 10

释放锁

命令:

# 释放锁,删除即可
DEL key

基于redisson看门狗机制(锁的续期)

redis加锁时,如果不自己定义参数中的leaseTime(锁自动释放时间),或者定义的leaseTime为-1,那么就会开启看门狗机制。(不定义的话,这个线程默认的leaseTime就是30s)

boolean tryLock(long waitTime, long leaseTime, TimeUnit unit);

看门狗机制就是当一个线程A加锁成功,且达到看门狗机制的触发条件时,会额外开一个线程,一般命名为Watch dog,这个线程每隔(releaseTime/3)的时间就为A续期时间,即重置过期时间。一般这个续期时间为锁的有效时间的一半,也可以自己额外设置。
在该锁有效期间,如果有其他线程想要试图加锁,那么就会不断while循环重试。

而采用了看门狗机制的锁的释放,是需要手动完成的,释放完成后还需要通知看门狗线程。

需要注意的是,加锁、设置过期时间等操作都是基于lua脚本完成的,因为能保证操作的原子性

代码模板

public void redisLock() throws InterruptedException{RLock lock = redissonClient.getLock("heimalock");try{boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);if(isLock){System.out.println("执行业务……");}}finally{lock.unlock();}
}

可重入性

锁的可重入性指的是同一个线程在持有锁的情况下,能够多次获取该锁而不会发生死锁或阻塞的情况。可重入锁的一个典型应用场景是在一个方法中调用另一个加锁的方法,譬如以下代码。如果方法A在获取锁后调用了方法B,而方法B也需要获取同一个锁,那么如果锁是可重入的,方法B可以直接获取到锁,而不会因为锁已被方法A持有而发生死锁。

public void add1(){RLock lock = redissonClient.getLock(“heimalock");boolean isLock = lock.tryLock();    //执行业务  add2();//释放锁lock.unlock();
}
public void add2(){RLock lock = redissonClient.getLock(“heimalock");boolean isLock = lock.tryLock();//执行业务//释放锁lock.unlock();
}

基于redisson实现的分布式锁是拥有可重入性的。
其中的KEY一般称为大键,可以根据自己的业务来命名。
field一般称为小键,是当前线程的唯一标识。
value记录着当前线程重入的次数。
在这里插入图片描述

主从一致性

对于多线程的主从一致性,实际上redisson没办法很好地保障。
像是原本如下运行,一个主库,两个从库,且java应用程序对主库进行加锁。
在这里插入图片描述
因为某种原因,主库短暂宕机,此时根据哨兵模式选举了下面的从库为新的主库。
此时又有个新的java应用来对这个新的主库进行加锁。那么就会出现两个线程同时持有一把锁的情况。
在这里插入图片描述

redlock红锁

为此,redisson提出了一个叫RedLock,红锁。
RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁(n / 2 + 1),避免在一个redis实例上加锁。即,在超过一半的实例上进行加锁。但是这种机制实现复杂,性能较差,运维起来也很繁琐。所以实际开发中很少用。

AP思想和CP思想

综上,对于多线程的主从一致性,实际上redis没办法很好地保障。因为redis本身是AP思想。

AP思想(可用性与分区容忍):
AP思想注重系统的可用性和分区容忍性,即在遇到网络分区或节点故障的情况下,系统仍然能够提供服务并保持可用性。这意味着系统可以容忍一定程度的数据不一致或冲突,以保证用户的访问体验。

如果想要强一致性,建议使用CP思想的zookeeper。

CP思想(一致性与分区容忍):
CP思想注重系统的一致性和分区容忍性,即在分布式环境中保持数据的一致性,并且即使发生网络分区,系统也能保持一致性。这种设计思想追求强一致性,确保所有节点中的数据都是一致的,但可能会导致一些节点不可用。

面试回答模板

Redis分布式锁如何实现 ?

候选人:嗯,在redis中提供了一个命令setnx(SET if not exists)

由于redis的单线程的,用了命令之后,只能有一个客户端对某一个key设置值,在没有过期或删除key的时候是其他客户端是不能设置这个key的

面试官:好的,那你如何控制Redis实现分布式锁有效时长呢?

候选人:嗯,的确,redis的setnx指令不好控制这个问题,我们当时采用的redis的一个框架redisson实现的。

在redisson中需要手动加锁,并且可以控制锁的失效时间和等待时间,当锁住的一个业务还没有执行完成的时候,在redisson中引入了一个看门狗机制,就是说每隔一段时间就检查当前业务是否还持有锁,如果持有就增加加锁的持有时间,当业务执行完成之后需要使用释放锁就可以了

还有一个好处就是,在高并发下,一个业务有可能会执行很快,先客户1持有锁的时候,客户2来了以后并不会马上拒绝,它会自旋不断尝试获取锁,如果客户1释放之后,客户2就可以马上持有锁,性能也得到了提升。

面试官:好的,redisson实现的分布式锁是可重入的吗?

候选人:嗯,是可以重入的。这样做是为了避免死锁的产生。这个重入其实在内部就是判断是否是当前线程持有的锁,如果是当前线程持有的锁就会计数,如果释放锁就会在计算上减一。在存储数据的时候采用的hash结构,大key可以按照自己的业务进行定制,其中小key是当前线程的唯一标识,value是当前线程重入的次数

面试官:redisson实现的分布式锁能解决主从一致性的问题吗

候选人:这个是不能的,比如,当线程1加锁成功后,master节点数据会异步复制到slave节点,此时当前持有Redis锁的master节点宕机,slave节点被提升为新的master节点,假如现在来了一个线程2,再次加锁,会在新的master节点上加锁成功,这个时候就会出现两个节点同时持有一把锁的问题。

我们可以利用redisson提供的红锁来解决这个问题,它的主要作用是,不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁,并且要求在大多数redis节点上都成功创建锁,红锁中要求是redis的节点数量要过半。这样就能避免线程1加锁成功后master节点宕机导致线程2成功加锁到新的master节点上的问题了。

但是,如果使用了红锁,因为需要同时在多个节点上都添加锁,性能就变的很低了,并且运维维护成本也非常高,所以,我们一般在项目中也不会直接使用红锁,并且官方也暂时废弃了这个红锁

面试官:好的,如果业务非要保证数据的强一致性,这个该怎么解决呢?

**候选人:**嗯~,redis本身就是支持高可用的,做到强一致性,就非常影响性能,所以,如果有强一致性要求高的业务,建议使用zookeeper实现的分布式锁,它是可以保证强一致性的。

这篇关于redis:六、数据过期删除策略(惰性删除、定期删除)和基于redisson实现的分布式锁(看门狗机制、主从一致性)和面试模板的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511180

相关文章

Redis分片集群的实现

《Redis分片集群的实现》Redis分片集群是一种将Redis数据库分散到多个节点上的方式,以提供更高的性能和可伸缩性,本文主要介绍了Redis分片集群的实现,具有一定的参考价值,感兴趣的可以了解一... 目录1. Redis Cluster的核心概念哈希槽(Hash Slots)主从复制与故障转移2.

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

使用Python实现一键隐藏屏幕并锁定输入

《使用Python实现一键隐藏屏幕并锁定输入》本文主要介绍了使用Python编写一个一键隐藏屏幕并锁定输入的黑科技程序,能够在指定热键触发后立即遮挡屏幕,并禁止一切键盘鼠标输入,这样就再也不用担心自己... 目录1. 概述2. 功能亮点3.代码实现4.使用方法5. 展示效果6. 代码优化与拓展7. 总结1.

Mybatis 传参与排序模糊查询功能实现

《Mybatis传参与排序模糊查询功能实现》:本文主要介绍Mybatis传参与排序模糊查询功能实现,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、#{ }和${ }传参的区别二、排序三、like查询四、数据库连接池五、mysql 开发企业规范一、#{ }和${ }传参的

Docker镜像修改hosts及dockerfile修改hosts文件的实现方式

《Docker镜像修改hosts及dockerfile修改hosts文件的实现方式》:本文主要介绍Docker镜像修改hosts及dockerfile修改hosts文件的实现方式,具有很好的参考价... 目录docker镜像修改hosts及dockerfile修改hosts文件准备 dockerfile 文

基于SpringBoot+Mybatis实现Mysql分表

《基于SpringBoot+Mybatis实现Mysql分表》这篇文章主要为大家详细介绍了基于SpringBoot+Mybatis实现Mysql分表的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录基本思路定义注解创建ThreadLocal创建拦截器业务处理基本思路1.根据创建时间字段按年进

Python获取中国节假日数据记录入JSON文件

《Python获取中国节假日数据记录入JSON文件》项目系统内置的日历应用为了提升用户体验,特别设置了在调休日期显示“休”的UI图标功能,那么问题是这些调休数据从哪里来呢?我尝试一种更为智能的方法:P... 目录节假日数据获取存入jsON文件节假日数据读取封装完整代码项目系统内置的日历应用为了提升用户体验,

SpringBoot3实现Gzip压缩优化的技术指南

《SpringBoot3实现Gzip压缩优化的技术指南》随着Web应用的用户量和数据量增加,网络带宽和页面加载速度逐渐成为瓶颈,为了减少数据传输量,提高用户体验,我们可以使用Gzip压缩HTTP响应,... 目录1、简述2、配置2.1 添加依赖2.2 配置 Gzip 压缩3、服务端应用4、前端应用4.1 N

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整