我们知道:Redis是基于内存的,面试官问:
- 生产环境Redis内存如何分配?
- Redis键过期了如何删除?
- ......
本小节不仅适用于工作,也是面试的高频问题。
文章导读
Redis内存分析
1.Redis默认内存是多少?
在 64bit 系统下,默认不限制内存大小,不设置内存大小和maxmemory = 0表示不限制 Redis 内存使用
2.如何查看Redis最大内存是多少?
命令行:
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"
配置文件 redis.conf:
# maxmemory <bytes>
3.如何查看Redis内存使用情况?
127.0.0.1:6379> info memory
4.如何配置和修改?
临时方案,通过命令修改:
127.0.0.1:6379> config set maxmemory 104857600
OK
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "104857600"
永久方案,通过配置文件:
5.生产环境如何配置?
建议:一般取物理内存的3/4
Redis过期键删除?
我们知道,redis一般会设置过期时间。那么这些键过期了是立刻从内存中删除吗?
通常,键删除会有不同的策略。
1.立刻删除
立即删除能保证过期键值会在过期后马上被删除,其所占用的内存也会随之释放。但是删除操作会占用cpu的时间,造成CPU额外的压力。
redis.conf 中,通过调整过期键的检测频率:
# The range is between 1 and 500, however a value over 100 is usually not
# a good idea. Most users should use the default of 10 and raise this up to
# 100 only in environments where very low latency is required.
hz 10
但是这会产生大量的性能消耗,同时也会影响数据的读取操作。
2.惰性删除
数据到达过期时间,不做处理。等下次访问该数据时:
- 如果未过期,返回数据 ;
- 发现已过期,删除,返回不存在。
惰性删除策略的缺点是,它对内存是最不友好的。如果一个键已经过期,而这个键又仍然保留在redis中,那么只要这个过期键不被删除,它所占用的内存就不会释放。
#开启憜性淘汰
lazyfree-lazy-eviction=yes
3.定期删除
这种方案有效规避上述两种极端情况, 定期删除策略的难点是确定删除操作执行的时长和频率:
- 如果删除操作执行得太频繁或者执行的时间太长,定期删除策略就会退化成立即删除策略。
- 如果删除操作执行得太少,或者执行的时间太短,定期删除策略又会和惰性删除束略一样,出现浪费内存的情况。
- 因此,如果采用定期删除策略的话,服务器必须根据情况,合理地设置删除操作的执行时长和执行频率。
Redis内存淘汰策略
基于上述的了解,假如:
- 定期删除时,从来没有被抽查到
- 惰性删除时,也从来没有被点中使用过
上述两个步骤,依然会有大量过期的key堆积在内存中,导致redis内存空间紧张或者很快耗尽。
因此,有没有一个更好的兜底方案......?这就是要讲的淘汰策略
1.LRU和LFU区别?
(1) LRU(Least Recently Used,最近最少使用页面置换算法)
假设我们有一个容量为3的LRU缓存,访问数据的顺序如下:
- 访问数据1,缓存中现在有:[1]
- 访问数据2,缓存中现在有:[1, 2]
- 访问数据3,缓存中现在有:[1, 2, 3]
- 再次访问数据1,缓存中现在有:[2, 3, 1](因为1被重新访问,它被移到了列表的末尾)
- 访问数据4,由于缓存已满,最不常用的数据2将被淘汰,缓存中现在有:[3, 1, 4]
原理:如果数据最近被访问过,那么在不久的将来它很可能再次被访问。因此,LRU会淘汰最长时间未被访问的数据。
适用场景:适用于最近被访问的数据在未来某个时间点很可能再次被访问。
(2) LFU(Least Frequently Used,最近最不常用页面置换算法)
假设我们有一个容量为3的LFU缓存,访问数据的顺序如下:
- 访问数据1,计数器:{1: 1}
- 访问数据2,计数器:{1: 1, 2: 1}
- 访问数据1,计数器:{1: 2, 2: 1}
- 访问数据3,计数器:{1: 2, 2: 1, 3: 1}
- 访问数据1,计数器:{1: 3, 2: 1, 3: 1}
- 访问数据4,由于缓存已满,访问次数最少的数据2将被淘汰,计数器:{1: 3, 3: 1, 4: 1}
原理:LFU算法会跟踪每个页面在特定时间段内被访问的频率。当需要淘汰页面时,LFU算法会淘汰在该时间段内访问次数最少的页面。
适用场景:LFU算法适用于那些访问模式可能随时间变化的场景,或者访问频率能够较好地反映页面重要性的情况。
(3) 小结
- LRU关注数据的最近访问时间,淘汰最长时间未被访问的数据。
- LFU关注数据的访问频率,淘汰访问次数最少的数据。
2.Redis有哪些淘汰策略?
redis.config 配置文件中,
# volatile-lru -> Evict using approximated LRU, only keys with an expire set.
# allkeys-lru -> Evict any key using approximated LRU.
# volatile-lfu -> Evict using approximated LFU, only keys with an expire set.
# allkeys-lfu -> Evict any key using approximated LFU.
# volatile-random -> Remove a random key having an expire set.
# allkeys-random -> Remove a random key, any key.
# volatile-ttl -> Remove the key with the nearest expire time (minor TTL)
# noeviction -> Don't evict anything, just return an error on write operations.
解释下:
- volatile-lru:使用近似的最近最少使用(LRU)算法淘汰键。但是,只有那些设置了过期时间的键(即“volatile”键)才会被考虑淘汰。
- allkeys-lru:使用近似的LRU算法淘汰任何键,无论它们是否设置了过期时间。
- volatile-lfu:使用近似的最少频率使用(LFU)算法淘汰键。同样,只有设置了过期时间的键会被考虑。
- allkeys-lfu:使用近似的LFU算法淘汰任何键,不考虑它们是否设置了过期时间。
- volatile-random:随机淘汰一个设置了过期时间的键。
- allkeys-random:随机淘汰任何键,不论它们是否设置了过期时间。
- volatile-ttl:淘汰具有最短剩余生存时间(TTL)的键,即那些最接近过期时间的键。
- noeviction:不淘汰任何键。当内存达到最大容量时,Redis将不会进行任何淘汰操作,而是在写入新数据时返回错误。
3.生产如何选择淘汰策略?
在生产环境中选择缓存淘汰策略时,通常需要根据应用的具体需求和数据特性来定。这里给出常见案例:
(1) 电商平台的商品推荐
电商平台需要为用户展示个性化的商品推荐,其中热门商品的访问频率较高。可选择:LFU(Least Frequently Used)
redis-cli config set maxmemory-policy allkeys-lfu
因为LFU策略可以保留访问频率高的商品,确保推荐列表中展示用户最可能感兴趣的商品。
(2) 金融交易平台的实时数据
金融交易平台需要提供实时的股票价格和交易数据,数据的实时性至关重要。过期的时价被淘汰。
可选择:TTL(Time To Live)结合LRU(Least Recently Used)
redis-cli config set maxmemory-policy volatile-lru
TTL确保数据在一定时间后自动过期,而LRU保证最近访问的数据被优先保留。
(3) 电信运营商的用户数据管理
电信运营商需要处理和缓存大量用户的通话记录、短信记录等,用户通常更关心最近的通信记录。
可选择:LRU(Least Recently Used)
redis-cli config set maxmemory-policy allkeys-lru
因为LRU策略可以确保最近生成的通话记录和短信记录被优先缓存。
(4) 社交媒体平台的用户动态
社交媒体平台需要为用户展示好友的最新动态和帖子,用户通常对最新动态感兴趣。
可选择:LRU
redis-cli config set maxmemory-policy allkeys-lru
因为LRU可以保证最新的帖子被优先展示。
好了,今天就聊到这里,读者可依据实际情况择优选择策略。