本文归于合集:深入Redis系列
本期我们介绍Redis的内存管理和缓存淘汰。
我们知道为了保证较高的性价比,缓存的空间容量必然要小于后端数据库的数据总量。随着要缓存的数据量越来越大,有限的缓存空间不可避免地会被写满。
解决这个问题就涉及到缓存系统的一个重要机制,即缓存数据的淘汰机制。数据淘汰机制包括两步:第一,根据一定的策略,筛选出对应用访问来说“不重要”的数据;第二,将这些数据从缓存中删除,为新来的数据腾出空间。
然而在正式介绍Redis的缓存淘汰机制之前,我们不妨关注一个问题:以系统在DB的数据量为基准,你会为你的系统缓存设置百分之多少的容量?
根据数据访问的局部性原理,在大多数的业务场景下,80% 的请求实际只访问了 20% 的数据(八二原理)。
如下图所示:
蓝线代表了“八二原理”表示的数据局部性,而红线则表示在当前应用负载下的数据局部性。蓝线描述的是正常情况下有 20% 的数据贡献了 80% 的访问量。这 80% 的数据在访问量上就形成了一条长长的尾巴,我们也称为“长尾效应”。
真实业务中,用户的个性化需求越来越多,在一个业务应用中,不同用户访问的内容可能差别很大,所以20% 的数据可能贡献不了 80% 的访问,而剩余的 80% 数据反而贡献了更多的访问量,我们称之为重尾效应。因此缓存容量占总数据量的比例,从 5% 到 40% 的都有,需要结合应用数据实际访问特征综合考虑的。一般来说,会建议把缓存容量设置为总数据量的 15% 到 30%,兼顾访问性能和内存空间开销。
说完了如何设置缓存容量以及依据之后,我们开始Redis内存管理的正题。
一、Redis内存组成、内存分配和释放
内存分配过程
内存释放过程
二、Redis的键值过期处理策略
Redis的键值过期策略是内存管理中的重要一环。这里首先需要说一下,可能会有人将Redis的过期策略和淘汰策略给搞混,但其实两者并不是一回事。
Redis的过期策略是指对设置了过期时间的键进行管理,当这些键的过期时间到达时,Redis会采取相应的操作来删除这些键。其主要作用是确保Redis中存储的数据是有效的、最新的,并且防止无用数据长期占用内存资源。其触发条件是键的过期时间到达,这可以通过Redis的EXPIRE、PEXPIRE等命令来设置键的过期时间。
Redis的淘汰策略是指在内存使用达到上限时,为了保持Redis的稳定运行和内存的有效利用,Redis会采取一系列措施来淘汰部分键。淘汰策略的主要作用是防止Redis内存溢出,确保Redis能够持续稳定地提供服务。淘汰策略的触发条件是Redis的内存使用达到或超过其配置的最大内存限制(maxmemory)。
从作用对象来说,过期策略作用于设置了过期时间的键,而淘汰策略则可能作用于整个Redis实例中的所有键(取决于具体的淘汰策略)。
Redis的淘汰策略会在下面介绍,这里回到过期策略。
惰性删除
定期删除
三、Redis的键值淘汰策略
首先为什么Redis需要淘汰策略呢?如果让大家回答这个问题,可能大家想到的可能只有:因为内存满了,所以需要根据一定的策略淘汰掉一些旧的或者少用的键值来存储新的或者常用的键值。但其实还可以从性能、数据一致性、内存成本和应对突发流量等角度来回答这个问题。
那么Redis的整体淘汰键值的流程是怎么样的呢?
内存检测
淘汰策略选择
数据取样
淘汰池维护
数据删除
上面的Redis淘汰流程中说到,Redis会根据具体的淘汰策略来决定哪些键值应该被淘汰,下面介绍一下Redis的淘汰策略。
其实Redis的键值淘汰策略遵循主流的内存淘汰算法:LFU和LRU算法。所以在说具体的淘汰策略之前,我会先简单介绍下这两种算法的特点和实现。
LRU算法
LFU算法
三、对比与选择
了解了LRU和LFU算法是怎么一回事之后,我们再看看Redis具体的淘汰策略。Redis的主要淘汰机制及其适用场景如下:
1. noeviction(不淘汰)
2. allkeys-lru(从所有key中使用LRU算法淘汰)
3. volatile-lru(从设置了过期时间的key中使用LRU算法淘汰)
4. allkeys-random(从所有key中随机淘汰)
5. volatile-random(从设置了过期时间的key中随机淘汰)
6. volatile-ttl(淘汰过期时间剩余最短的)
7. allkeys-lfu(从所有key中使用LFU算法淘汰,如果Redis版本支持)
8. volatile-lfu(从设置了过期时间的key中使用LFU算法淘汰,如果Redis版本支持)
欢迎在评论区留言表达看法和问题,阿沛会一一作出回复。
如果本文对大家有帮助,麻烦大家动动小手点个免费的“赞”或“在看”,大家的鼓励就是阿沛持续更新的动力~
-- 往期精彩 --
面试题:BIO,NIO,AIO 的区别是什么?说说select 和 epoll 工作机制与差异?为何epoll 如此高效
阿里一面:说说看线程池的执行流程和原理?线程池的拒绝策略有哪些?如何确定线程池的核心线程数?如何优雅的关闭线程池?
面试题:说说看你对数据库事务和ACID的理解?并发事务可能会产生哪些问题,该如何解决?什么是快照读和MVCC,解决了什么问题?
面试题:说说看进程、线程和协程的区别是什么?协程能够并行吗?Goroutine和Coroutine的区别是什么?