外包网站都有哪些,网站jianshe,wordpress中文美食主题,北京网站建设itcask数据过期策略和淘汰策略
过期策略
Redis所有的数据结构都可以设置过期时间#xff0c;时间一到#xff0c;就会自动删除。
问题#xff1a;大家都知道#xff0c;Redis是单线程的#xff0c;如果同一时间太多key过期#xff0c;Redis删除的时间也会占用线程的处理时间…数据过期策略和淘汰策略
过期策略
Redis所有的数据结构都可以设置过期时间时间一到就会自动删除。
问题大家都知道Redis是单线程的如果同一时间太多key过期Redis删除的时间也会占用线程的处理时间如果删除的太过于频繁会不会导致线上读写指令出现卡顿
这些问题Redis作者 Antirez 早就想到了所以在过期这件事上Redis非常小心 。
两种删除策略
定时扫描策略集中处理惰性删除策略零散处理
定时扫描策略
redis将每个设置了过期时间的 key 放入到一个独立的字典中以后会定时遍历这个字典来删除到期的key。
具体流程
Redis默认会每秒进行十次过期扫描过期扫描不会遍历过期字典中所有的key而是采用了一种简单的贪心策略。
从过期字典中随机选择20个key删除这20个key中已经过期的key如果过期的key比率超过1/4那就重复步骤1
同时为了保证过期扫描不会出现循环过度导致线程卡死现象算法还增加了扫描时间的上限默认不会超过25ms。
问题设想一个大型的Redis实例中所有的key在同一时间过期了会出现怎样的结果
毫无疑问Redis会持续扫描过期字典循环多次直到过期字典中过期的 key 变得稀疏才会停止循环次数明显下降。这就会导致线上读写请求出现明显卡顿现象。导致这种卡顿的另外一种原因是内存管理器需要频繁回收内存页这也会产生一定的CPU消耗。
但是我们不是已经有25ms的时间上限了么怎么会导致卡顿呢
eg 假如有101个客户端同时将请求发过来了然后前100个请求的执行时间都是25ms那么第101个指令需要等待多久才能执行
答案2500ms这个就是客户端的卡顿时间是由服务器不间断的小卡顿积少成多导致的。
所以业务开发人员一定要注意过期时间如果有大批量的key过期要给过期时间设置一个随机范围而不能全部在同一时间过期。 在目标过期时间上增加一天的随机时间 redis.expire_at(key, random.randint(86400) expire_ts) 惰性删除策略
惰性删除策略就是在客户端访问这个key的时候redis对key的过期时间进行检查如果过期了就立即删除。
淘汰策略
上面说的过期删除策略是删除已过期的key而当Redis的运行内存已经超过Redis设置的最大内存之后则会使用内存淘汰策略删除符合条件的key以此来保障Redis高效的运行。
如何设置Redis最大运行内存
在配置文件redis.conf中可以通过参数maxmemory bytes来设定最大运行内存只有在Redis的运行内存达到了我们设置的最大运行内存才会触发内存淘汰策略。不同位数的操作系统maxmemory的默认值是不同的。
在64位操作系统中maxmemory的默认值是0表示没有内存大小限制那么不管用户存放多少数据到Redis中Redis也不会对可用内存进行检查直到Redis实例因内存不足而崩溃也无作为。在32位操作系统中maxmemory的默认值是3G因为32位的机器最大只支持4GB的内存而系统本身就需要一定的内存资源来支持运行所以32位操作系统限制最大 3GB 的可用内存是非常合理的这样可以避免因为内存不足而导致Redis实例崩溃。
Redis内存淘汰策略有哪些
不进行数据淘汰的策略
noeviction(Redis3.0之后默认的内存淘汰策略)它表示当运行内存超过最大设置内存时 不淘汰任何数据这时如果有新的数据写入会报错通知禁止写入不淘汰任何数据但是如果没用数据写入的话只是单纯的查询或者删除操作的话还是可以正常工作。
进行数据淘汰的策略
在设置了过期时间的数据中进行淘汰
valatile-random随机淘汰了设置了过期时间的任意键值volatile-ttl优先淘汰更早过期的键值volatile-lruRedis3.0之前默认的内存淘汰策略淘汰所有设置了过期时间的键值中最久未使用的键值volatile-lfuRedis4.0后新增的内存淘汰策略淘汰所有设置了过期时间的键值中最少使用的键值。
在所有数据范围内进行淘汰
allkeys-random随机淘汰任意键值allkeys-lru淘汰整个键值中最久未使用的键值allkeys-lfuRedis 4.0 后新增的内存淘汰策略淘汰整个键值中最少使用的键值。
如何修改Redis内存淘汰策略
设置内存淘汰策略的两种方法
方式一通过config set maxmemory-policy 策略命令设置。它的优点是设置之后立即生效不需要重启Redis服务缺点是重启Redis之后设置就会失效。方式二通过修改Redis配置文件修改设置maxmemory-policy 策略它的优点是重启Redis服务后配置不会丢失缺点是必须重启Redis服务设置才能生效。
LRU算法和LFU算法有什么区别 什么是LRU算法 LRU 全称是 Least Recently Used翻译为最近最少使用会选择淘汰最近最少使用的数据。
传统的 LRU 算法的实现是基于【链表】结构链表中的元素按照操作顺序从前往后排列最新操作的键会被移动到表头当需要内存淘汰时只需要删除链表尾部的元素即可因为链表尾部的元素就代表最久未被使用的元素。
Redis并没有使用这样的方式实现LRU算法因为传统的LRU算法存在两个问题
需要用链表管理所有的缓存数据这会带来额外的空间开销当有数据被访问时需要在链表上把该数据移动到头端如果有大量数据被访问就会带来很多链表移动操作会很耗时进而会降低Redis缓存性能。 Redis是如何实现LRU算法的 Redis 实现的是一种近似LRU算法目的是为了更好的节约内存它的实现方式是在Redis的对象结构体中添加一个额外的字段用于记录此数据的最后一次访问时间。
当Redis 进行内存淘汰时会使用随机采样的方式来淘汰数据它是随机取 5 个值个数可配置然后淘汰最久没有使用的那个。
Redis实现的LRU算法的优点
不用为所有的数据维护一个大链表节省了空间占用不用在每次数据访问时都移动链表项提升了缓存的性能。
但是LRU算法有一个问题无法解决缓存污染问题比如应用依次读取了大量的数据而这些数据只会被读取这一次那么这些数据会留存在 Redis 缓存中很长一段时间造成缓存污染
因此在Redis 4.0 之后引入了LFU算法来解决这个问题。 什么时LFU算法 LFU全程是 Least Frequently Used翻译为最近最不常用LFU算法是根据数据访问次数来淘汰数据的它的核心思想是“如果数据过去被访问多次那么将来被访问的频率也更高”。
所以LFU算法会记录每个数据的访问次数。当一个数据被再次访问时就会增加该数据的访问次数。这样就解决了偶尔被访问一次之后数据留存在缓存中很长一段时间的问题相比于LRU算法也更合理一些。
实现
typedef struct redisObject {...// 24 bits用于记录对象的访问信息unsigned lru:24; ...
} robj;Redis 对象头中的 lru 字段在 LRU 算法下和 LFU 算法下使用方式并不相同。
在 LRU 算法中Redis 对象头的 24 bits 的 lru 字段是用来记录 key 的访问时间戳因此在 LRU 模式下Redis可以根据对象头中的 lru 字段记录的值来比较最后一次 key 的访问时间长从而淘汰最久未被使用的 key。
在 LFU 算法中Redis对象头的 24 bits 的 lru 字段被分成两段来存储高 16bit 存储 ldt(Last Decrement Time)低 8bit 存储 logc(Logistic Counter)。 ldt 是用来记录 key 的访问时间戳logc 是用来记录 key 的访问频次它的值越小表示使用频率越低越容易淘汰每个新加入的 key 的logc 初始值为 5。
注意logc 并不是单纯的访问次数而是访问频次访问频率因为 logc 会随时间推移而衰减的。
在每次 key 被访问时会先对 logc 做一个衰减操作衰减的值跟前后访问时间的差距有关系如果上一次访问的时间与这一次访问的时间差距很大那么衰减的值就越大这样实现的 LFU 算法是根据访问频率来淘汰数据的而不只是访问次数。访问频率需要考虑 key 的访问是多长时间段内发生的。key 的先前访问距离当前时间越长那么这个 key 的访问频率相应地也就会降低这样被淘汰的概率也会更大。
对 logc 做完衰减操作后就开始对 logc 进行增加操作增加操作并不是单纯的 1而是根据概率增加如果 logc 越大的 key它的 logc 就越难再增加。
所以Redis 在访问 key 时对于 logc 是这样变化的
先按照上次访问距离当前的时长来对 logc 进行衰减然后再按照一定概率增加 logc 的值
redis.conf 提供了两个配置项用于调整 LFU 算法从而控制 logc 的增长和衰减 lfu-decay-time 用于调整 logc 的衰减速度它是一个以分钟为单位的数值默认值为1lfu-decay-time 值越大衰减越慢lfu-log-factor 用于调整 logc 的增长速度lfu-log-factor 值越大logc 增长越慢。