目录
一、Redis的内存淘汰策略
1.1. 概念
1.2.策略一:全局的键空间选择性移除
1.3.策略二:设置过期时间的键空间选择性移除
1.4.LRU、LFU和volatile-ttl都是近似随机算法
1.4.1.LRU算法
1.4.2.LFU算法
1.5.过期删除策略
1.6.AOF和RDB的过期删除策略
二、REDIS的消耗及优化
2.1.消耗状态
2.2.优化
2.2.1.Redis的内存优化
2.2.2.避免使用KEYS
2.2.3.设置 key 有效期
2.2.4.选择回收策略
2.2.5.限制redis的内存大小
2.2.6.部署和场景应用优化
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
注:Redis的内存淘汰策略的选取并不会影响过期的key的处理。内存淘汰策略用于处理内存不足时的需要申请额外空间的数据;过期策略用于处理过期的缓存数据。
使用下面的参数maxmemory-policy配置淘汰策略:
#配置文件
maxmemory-policy noeviction
#命令行
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "noeviction"
127.0.0.1:6379> config set maxmemory-policy allkeys-random
OK
127.0.0.1:6379> config get maxmemory-policy
1) "maxmemory-policy"
2) "allkeys-random"
LRU(Least Recently Used)表示最近最少使用,该算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
新数据放在链表头部 ,链表中的数据被访问就移动到链头,链表满的时候从链表尾部移出数据。
而在Redis中使用的是近似LRU算法,为什么说是近似呢?Redis中是随机采样5个(可以修改参数maxmemory-samples配置)key,然后从中选择访问时间最早的key进行淘汰,因此当采样key的数量与Redis库中key的数量越接近,淘汰的规则就越接近LRU算法。但官方推荐5个就足够了,最多不超过10个,越大就越消耗CPU的资源。
但在LRU算法下,如果一个热点数据最近很少访问,而非热点数据近期访问了,就会误把热点数据淘汰而留下了非热点数据,因此在Redis4.x中新增了LFU算法。
注:在LRU算法下,Redis会为每个key新增一个3字节的内存空间用于存储key的访问时间;
LFU(Least Frequently Used)表示最不经常使用,它是根据数据的历史访问频率来淘汰数据,其核心思想是“如果数据过去被访问多次,那么将来被访问的频率也更高”。
解决LRU算法的漏洞:LFU算法反映了一个key的热度情况,不会因LRU算法的偶尔一次被访问被误认为是热点数据。
新数据放在链表尾部 ,链表中的数据按照被访问次数降序排列,访问次数相同的按最近访问时间降序排列,链表满的时候从链表尾部移出数据。
前面介绍的LRU和LFU算法都是在Redis内存占用满的情况下的淘汰策略,那么当内存没占满时在Redis中过期的key是如何从内存中删除以达到优化内存占用的呢?
在Redis中过期的key不会立刻从内存中删除,而是会同时以下面两种策略进行删除:
扫描周期:Redis每10秒进行一次过期扫描:
前面介绍了Redis的持久化策略RDB和AOF,当Redis中的key已过期未删除时,如果进行RDB和AOF的持久化操作时候会怎么操作呢?
注: 这四个命令都不会将过期key持久化到RDB文件或AOF文件中,可以保证重启服务时不会将过期key载入Redis。
为了保证一致性,在AOF持久化模式中,当key过期时候,会同时发送DEL命令给AOF文件和所有节点;从节点不会主动的删除过期key除非它升级为主节点或收到主节点发来的DEL命令;
Redis主要消耗什么物理资源?那自然是内存,大家都知道,内存资源一旦使用完,那么Redis会怎么样呢?
如果达到设置的上限,Redis的写命令会返回错误信息(但是读命令还可以正常返回)或者你可以配置内存淘汰机制,当Redis达到内存上限时会冲刷掉旧的内容。
利用Hash,list,sorted set,set等集合类型数据,因为通常情况下很多小的Key-Value可以用更紧凑的方式存放到一起。尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。
[root@localhost ~]# redis-cli
127.0.0.1:6379> info memory #查看内存使用总量和内存碎片率
# Memory
used_memory:11315280 #内存使用总量
used_memory_human:10.79M
mem_fragmentation_ratio:1.76 #内存碎片率
mem_fragmentation_bytes:8566768
注:那么内存使用率超过可用最大内存,redis响应速度会变慢,这个时候操作系统将开始进行内存与swap空间交换,就需要设置内存淘汰策略
应该尽可能的利用key有效期。比如一些临时数据(短信校验码),过了有效期Redis就会自动为你清除!
当 Redis 的实例空间被填满了之后,将会尝试回收一部分key。根据你的使用方式,强烈建议使用 volatile-lru(默认)策略——前提是你对key已经设置了超时。
数据量不可预估,并且内存也有限的话,尽量限制下redis使用的内存大小,这样可以避免redis使用swap分区或者出现OOM错误。(使用swap分区,性能较低,如果限制了内存,当到达指定内存之后就不能添加数据了,否则会报OOM错误。可以设置maxmemory-policy,内存不足时删除数据。)