在Redis中通过以下指令都能为key设置一个生命周期
sexex key seconds //只适用于String数据类型
expire key seconds
expireat key timestamp
pexpire key milliseconds
pexpireat key millitimestamp
当这些数据到期之后就真的删除了吗? 显然,这里会有删除策略,会在cpu和内存之间做个权衡
Redis是内存级的数据库,将所有数据都存放在内存中,可以通过ttl指令获取数据的状态
①xx:是具有时效性的数据
②-1:永久有效的数据
③-2:已经过期的数据或被删除的数据或未定义的数据
时效性数据在Redis中的内存结构:
数据删除策略:
1.定时删除
·创建一个定时器,当key设置有过期时间并且到达了过期时间,由定时器任务立即执行对key的删除
·优点:到时就删除,节省内存空间
·缺点:cpu的压力很大,无论此时CPU负载量多高,均会占用cpu,会影响redis服务器的响应时间和吞吐量
总结:用时间换空间
2.惰性删除
服务器是怎么知道key过没过期的?在执行get命令之前会调用expireIfNeed()函数来获取是否过期
·数据到期不删除,等下次再调用的时候再删除
·如果未过期直接调用
·如果过期则删除key,返回不在
·优点:节约CPU的性能,发现必须删除的时候才删除
·缺点:内存压力很大,出现长期占用内存的数据
总结:用空间换时间
3.定期删除
·Redis服务器启动时读取配置文件中的server.hz,默认为10
·Redis每秒要执行server.hz次serverCron()->databaseCron()->activeExpireCycle()
·activeExpireCycle()对每个expire[*]进行检查,每次检查时间为250ms/server.hz
·对某个expire[*]进行检查时,随机挑选出W个key检查
·如果key过期则删除key
·如果删除的key的个数>w*25%,则循环该过程
·如果删除key的个数<W*25%,则检查下一个expire[*],0-15循环
·W的取值=ACTIVE_EXPIRE_CYCLE_LOOKUPS_PRE_LOOP属性值
·current_db用来记录当前activeExpireCycle()在那个expire[*]执行
·如果activeExpireCycle()执行时间到了,下次从current_db继续向下执行
总结:定期删除策略采用周期性轮询redis库中的时效性数据,采用随机抽取的策略,利用过期数据占比的方式控制删除的频度
特点:①CPU占用设置峰值,检查频度可以自己设置②内存压力不是很大,长期占用内存的冷门数据会被持续清理
Redis默认使用:惰性删除和定期删除
三种删除策略的对比:
策略 | |||
定时删除 | 不占用内存 | CPU压力大 | 用时间换空间 |
惰性删除 | 占用内存,内存压力大 | 延时执行,CPU效率高 | 用空间换时间 |
定期删除 | 内存定期随机处理 | CPU每秒花费固定的时间维护内存 | 随机抽查、重点抽查 |
当新数据进入Redis时,内存不足怎么办?
Redis服务器在执行一条命令之前,会先调用freeMemoryIfNeeded()检测内存是否充足。如果内存不足以满足添加新数据的最低存储要求,则Redis会删除一些数据为当前指令清理空间,清理数据的策略成为逐出算法
注意:清理数据的过程不是100%能清理出足够的可使用的内存空间,如果空间不足则会反复执行,当对所有数据尝试完毕之后,内存空间还是不够则会报以下错误
影响数据逐出的相关配置:
·最大可用内存
maxmemory
占用物理内存的比例,默认是0,不受限制,在实际生成中,一般配置50%以上
·每次选取待删除个数
maxmemory-samples
选取删除的数据并不是全表扫描,严重损耗性能,降低IO性能。因此采用随机获取数据的方式作为待检测删除数据
·删除策略
maxmemory-policy
达到最大内存后的,对被挑选出来的数据进行删除的策略
·检查易失数据(server.db[i].expires)
①volatile-lru:删除最近最久未使用的数据
②volatile-lfu:删除最近使用次数最少的数据
③volatile-ttl:删除将要过期的数据
④volatile-random:随机删除数据
·检查全库数据(所有数据集server.db[i].dict)
⑤allkeys-lru:删除最近最久未使用的数据
⑥allkeys-lfu:删除最近使用最少的数据
⑦allkeys-random:随机删除数据
·放弃数据逐出
⑧non-enviction:禁止驱逐数据(redis4.0默认策略),会引起OOM
建议使用:①