一、redis的过期策略:

redis的过期策略是:定期删除+惰性删除
redis在存储数据时,可能会设置过期时间,而所谓的定期删除,指的是redis默认是每隔100ms就随机抽取一些设置了过期时间的key进行检查,如果过期了就会删除。
至于为啥是每隔100ms随机抽取一些数据进行检查而不是全部检查,这就与cpu负载有关了,如redis中的数据十分庞大,并且全部都设置了过期时间,依次全部检查并且进行删除的话负载太高,影响性能。
但是,由于是随机抽取的key进行检查进行删除,那么很多的key可能会到了过期时间了还没进行删除,那么怎么办呢?这时候,惰性删除就会发挥作用了,所谓的惰性删除,就是在读取某个key的时候,redis会先检查一个该key是否过期,如果过期了,就会在此时删除,然后不会给你返回任何东西。
但是此时就会产生另外一个问题,假如一些key设置了过期时间,而定期删除的随机抽取没有选中这些key,而恰好也没有人去获取这些key,惰性删除也发挥不了作用了,那么这些数据就会越积累越多,redis一般作为缓存的,是基于内存的,这些数据越来越多的时候回导致内存耗尽,影响性能,这时候应该怎么办呢?这时候,另一个重量型的武器就要发挥作用了,那就是:内存淘汰机制。


二、内存淘汰机制:

redis 内存淘汰机制(内存淘汰策略)有以下几个:
• noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。
• allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)。
• allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。
• volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 key(这个一般不太合适)。
• volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 key。
• volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 key 优先移除。

但是理论性的东西我们明白了,那么该如何配置内存淘汰策略呢?


三、内存淘汰策略的配置

我们通过配置redis.conf中的maxmemory这个值来开启内存淘汰功能。

# maxmemory

值得注意的是,maxmemory为0的时候表示我们对Redis的内存使用没有限制。

根据应用场景,选择淘汰策略

# maxmemory-policy noeviction

我们来了解下,内存淘汰的过程

首先,客户端发起了需要申请更多内存的命令(如set)。

然后,Redis检查内存使用情况,如果已使用的内存大于maxmemory则开始根据用户配置的不同淘汰策略来淘汰内存(key),从而换取一定的内存。

最后,如果上面都没问题,则这个命令执行成功。

动态改配置命令

此外,redis支持动态改配置,无需重启。

设置最大内存

config set maxmemory 100000

设置淘汰策略

config set maxmemory-policy noeviction

如何选择淘汰策略

下面看看几种策略的适用场景

allkeys-lru:如果我们的应用对缓存的访问符合幂律分布,也就是存在相对热点数据,或者我们不太清楚我们应用的缓存访问分布状况,我们可以选择allkeys-lru策略。

allkeys-random:如果我们的应用对于缓存key的访问概率相等,则可以使用这个策略。

volatile-ttl:这种策略使得我们可以向Redis提示哪些key更适合被eviction。

另外,volatile-lru策略和volatile-random策略适合我们将一个Redis实例既应用于缓存和又应用于持久化存储的时候,然而我们也可以通过使用两个Redis实例来达到相同的效果,值得一提的是将key设置过期时间实际上会消耗更多的内存,因此我们建议使用allkeys-lru策略从而更有效率的使用内存。


四、设置过期时间

redis有四种命令可以用于设置键的生存时间和过期时间:

EXPIRE <KEY> <TTL> : 将键的生存时间设为 ttl 秒
PEXPIRE <KEY> <TTL> :将键的生存时间设为 ttl 毫秒
EXPIREAT <KEY> <timestamp> :将键的过期时间设为 timestamp 所指定的秒数时间戳
PEXPIREAT <KEY> <timestamp>: 将键的过期时间设为 timestamp 所指定的毫秒数时间戳.

当然,平时我们也可以使用java代码的方式进行过期时间的设置,一些工具类可以直接满足要求,在这里,我就提供一个工具类:

 import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; /**
* redis的工具类
* @author zangchuanlei
* @date 2019.09.18
*/
@Component
public final class RedisUtil { @Autowired
private RedisTemplate<String,Object> redisTemplate; /**
* 指定缓存失效的时间
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key,long time){
try {
if(time > 0){
redisTemplate.expire(key,time,TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据key获取过期时间
* @param key 键 不能为null
* @return 时间(秒)返回0代表为永久有效
*/
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
} /**
* 判断key是否存在
* @param key 键
* @return true 存在 false 不存在
*/
public boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除缓存
* @param key 可以传一个值或者多个值
*/
public void del(String... key){
if(key != null && key.length > 0){
if(key.length == 1){
redisTemplate.delete(key[0]);
}else{
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
} //=========================String======================
/**
*普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key){
return key == null ? null : redisTemplate.opsForValue().get(key);
} /**
* 普通缓存的放入
* @param key
* @param value
* @return
*/
public boolean set(String key, Object value){
try {
redisTemplate.opsForValue().set(key,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0,如果time要是小于0,将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key,Object value,long time){
try {
if(time > 0){
redisTemplate.opsForValue().set(key,value,time,TimeUnit.SECONDS);
}else{
set(key,value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 递增
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key,long delta){
if(delta < 0){
throw new RuntimeException("增强因子必须大于0");
}
return redisTemplate.opsForValue().increment(key,delta);
} /**
* 递减
* @param key 键
* @param delta 要减少几(大于0)
* @return
*/
public long decr(String key,long delta){
if(delta < 0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key,-delta);
} /**
* HashGet
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key,String item){
return redisTemplate.opsForHash().get(key,item);
} /**
* 获取hashKey对应的所有的键值
* @param key 键
* @return 对应的多个键值
*/
public Map<Object,Object> hmget(String key){
return redisTemplate.opsForHash().entries(key);
} /**
* hashSet
* @param key 键
* @param map 对应多个键值
* @return true成功 false 失败
*/
public boolean hmset(String key,Map<String,Object> map){
try {
redisTemplate.opsForHash().putAll(key,map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* HashSet并设置时间
* @param key 键
* @param map 对应多个键值
* @param time 时间秒
* @return true 成功 false 失败
*/
public boolean hmset(String key,Map<String,Object> map,long time){
try {
redisTemplate.opsForHash().putAll(key,map);
if(time > 0){
expire(key,time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @return true成功 false失败
*/
public boolean hset(String key,String item,Object value){
try {
redisTemplate.opsForHash().put(key,item,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已经存在的hash表有时间,这里将会替换原有的时间
* @return true成功 false 失败
*/
public boolean hset(String key,String item,Object value,long time){
try {
redisTemplate.opsForHash().put(key,item,value);
if(time > 0){
expire(key,time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除hash表中的值
* @param key 键 不能为null
* @param item 项 可以使用多个 但不能为null
*/
public void hdel(String key,Object... item){
redisTemplate.opsForHash().delete(key,item);
} /**
* 判断hash表中是否有该项的值
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false 不存在
*/
public boolean hHasKey(String key,String item){
return redisTemplate.opsForHash().hasKey(key,item);
} /**
* hash递增 如果不存在,就会创建一个 把新增后的值返回
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key,String item,double by){
return redisTemplate.opsForHash().increment(key,item,by);
} /**
* hash递减 如果不存在,就会创建一个 把新增后的值返回
* @param key 键
* @param item 项
* @param by 要减少几(大于0)
* @return
*/
public double hdecr(String key,String item,double by){
return redisTemplate.opsForHash().increment(key,item,-by);
} //==========================set==================== /**
* 根据key获取set中的所有值
* @param key 键
* @return
*/
public Set<Object> sGet(String key){
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 根据value从一个set中查询,是否存在
* @param key 键
* @param value 值
* @return true存在 false不存在
*/
public boolean sHashKey(String key,Object value){
try {
return redisTemplate.opsForSet().isMember(key,value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将数据放入set缓存
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key,Object... values){
try {
return redisTemplate.opsForSet().add(key,values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 将set数据放入缓存并设置失效时间
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key,long time,Object... values){
try {
Long count = redisTemplate.opsForSet().add(key,values);
if(time > 0){
expire(key,time);
}
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 获取set缓存的长度
* @param key 键
* @return
*/
public long sGetSetSize(String key){
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 移除值为value的
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key,Object... values){
try {
Long count = redisTemplate.opsForSet().remove(key,values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} //===================list==================== /**
* 获取list缓存的内容
* @param key 键
* @param start 开始
* @param end 结束 0到-1代表所有值
* @return
*/
public List<Object> lGet(String key,long start,long end){
try {
return redisTemplate.opsForList().range(key,start,end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 获取list缓存的长度
* @param key 键
* @return
*/
public long lGetListSize(String key){
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 通过索引 获取list中的值
* @param key 键
* @param index 索引 index>=0, 0表头,1 第二个元素 ;
* 索引index<0时,-1,表尾,-2倒数第二个元素 以此类推
* @return
*/
public Object iGetIndex(String key,long index){
try {
return redisTemplate.opsForList().index(key,index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key,Object value){
try {
redisTemplate.opsForList().rightPush(key,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key,Object value,long time){
try {
redisTemplate.opsForList().rightPush(key,value);
if(time > 0){
expire(key,time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
* @param key 键
* @param value 值
* @return
*/
public boolean lSet(String key,List<Object> value){
try {
redisTemplate.opsForList().rightPushAll(key,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key,List<Object> value,long time){
try {
redisTemplate.opsForList().rightPushAll(key,value);
if(time > 0){
expire(key,time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据索引修改list中的某条数据
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key,long index,Object value){
try {
redisTemplate.opsForList().set(key,index,value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 移除N个值为value
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key,long count,Object value){
try {
Long remove = redisTemplate.opsForList().remove(key,count,value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} }

参考原文链接:https://blog.csdn.net/baidu_26954625/article/details/90648597

redis过期策略以及内存淘汰机制(理论+配置)的更多相关文章

  1. Redis(六)--- Redis过期策略与内存淘汰机制

    1.简述 关于Redis键的过期策略,首先要了解两种时间的区别,生存时间和过期时间: 生存时间:一段时长,如30秒.6000毫秒,设置键的生存时间就是设置这个键可以存在多长时间,命令有两个 expir ...

  2. redis过期策略和内存淘汰机制

    目录 常见的删除策略 redis使用的过期策略:定期删除+惰性删除 定期删除 惰性删除 为什么要采用定期删除+惰性删除2种策略呢? redis内存淘汰机制 常见的删除策略 1.定时删除:在设置键的过期 ...

  3. redis过期策略与内存淘汰机制分析

    过期策略: 我们在set key时,可以给一个expire time,就是过期时间 这段过期时间以后,redis对key删除使用:定期删除+惰性删除 定期删除指redis默认在100ms内随机抽取一些 ...

  4. redis过期策略、内存淘汰策略、持久化方式、主从复制

    原文链接:https://blog.csdn.net/a745233700/article/details/85413179 一.Redis的过期策略以及内存淘汰策略:1.过期策略:定期删除+惰性删除 ...

  5. Redis的过期策略和内存淘汰机制

    过期策略 我们set key的时候,都可以给一个expire time,就是过期时间,指定这个key比如说只能存活1个小时,我们自己可以指定缓存到期就失效. 如果假设你设置一个一批key只能存活1个小 ...

  6. redis的过期策略以及内存淘汰机制

    redis采用的是定期删除+惰性删除策略. 为什么不用定时删除策略? 定时删除,用一个定时器来负责监视key,过期则自动删除.虽然内存及时释放,但是十分消耗CPU资源.在大并发请求下,CPU要将时间应 ...

  7. 关于redis的几件小事(四)redis的过期策略以及内存淘汰机制

    1.数据为什么会过期? 首先,要明白redis是用来做数据缓存的,不是用来做数据存储的(当然也可以当数据库用),所以数据时候过期的,过期的数据就不见了,过期主要有两种情况, ①在设置缓存数据时制定了过 ...

  8. Redis的过期删除策略(和内存淘汰机制)-转

    版权声明:本文为CSDN博主「奥修诺斯」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/qq_39944869/ ...

  9. Redis 中的过期删除策略和内存淘汰机制

    Redis 中 key 的过期删除策略 前言 Redis 中 key 的过期删除策略 1.定时删除 2.惰性删除 3.定期删除 Redis 中过期删除策略 从库是否会脏读主库创建的过期键 内存淘汰机制 ...

随机推荐

  1. Spark本地配置

    1. 下载解压安装包 tar -xvf spark-2.0.2-bin-hadoop2.6.tgz tar -xvf scala-2.11.8.tgz 2. 修改Spark配置文件 cd spark- ...

  2. py_正则表达式练习

    正则表达式: #正则表达式 #键盘数字6上的符号,^表示行的开始,$ 表示行的结束 #test = "tm queal Tomorrow Moon" ''' ^tm #匹配tm开头 ...

  3. 记得设置docker日志文件大小!!!!!

    # vim /etc/docker/daemon.json { "log-driver":"json-file", "log-opts": ...

  4. 图解Janusgraph系列-分布式id生成策略分析

    JanusGraph - 分布式id的生成策略 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 本次更新时间:2020-9-1 文章为作者跟踪源码和查看官方文档整理,如有任何问题,请联 ...

  5. Forward Rendering VS Deferred Rendering

    http://gad.qq.com/article/detail/32731 Forward Rendering Deferred Rendering

  6. IntelliJ IDEA远程Debug Linux的Java程序,找问题不要只会看日志了

    1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! 我们习惯于在本地开发的时候debug,能快速定位与解决问题,那部署在服务器上是不是就没有办法了呢?只能通过查看日志来定位? ...

  7. Left Mouse Button (bfs)

    Mine sweeper is a very popular small game in Windows operating system. The object of the game is to ...

  8. java初探(1)之秒杀的业务简单实现

    前言 秒杀的业务场景广泛存在于电商当中,即有一个倒计时的时间限制,当倒计时为0时,秒杀开始,秒杀之后持续很小的一段时间,而且秒杀的商品很少,因此会有大量的顾客进行购买,会产生很大的并发量,从而创造技术 ...

  9. 数据库的表的字段名称与实体类(pojo)不对应解决方案

    数据库的表的字段名称与实体类(pojo)不对应解决方案 数据库表 ![image-20200429130200825](C:%5CUsers%5C%E6%9E%97%E6%AD%A3%E6%98%8E ...

  10. Kubernetes v1.12/v1.13 二进制部署集群(HTTPS+RBAC)

    官方提供的几种Kubernetes部署方式 minikube Minikube是一个工具,可以在本地快速运行一个单点的Kubernetes,尝试Kubernetes或日常开发的用户使用.不能用于生产环 ...