redis的过期策略
最近把内存淘汰策略和过期策略搞混了。。。。
Redis的过期策略就是指当Redis中缓存的key过期了,Redis是怎么处理的
Redis的过期策略有三种:
-
- 定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除操作,并释放过期键占用的内存。
优点:对内存友好
缺点:对CPU时间非常不友好
-
- 惰性删除
只有当访问到一个key时,才会检查key有没有过期,过期则删除,返回-1;没有过期则返回该键。
优点:对CPU时间非常友好
缺点:对内存非常不友好(存在键过期,但是一致没有访问到,则会一直存在内存中)
-
- 定期删除
每隔一段时间,程序对数据库进行一次检查,删除里面的过期key,至于要删除那些数据库的过期key,则由算法决定。
定期删除策略每隔一段时间执行一次删除过期键的操作,并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响,同时通过定期删除过期键,也有有效的减少了因为过期键带来的内存浪费。
Redis使用的是惰性删除和定期删除。
- 惰性删除的实现
Redis对所有读写数据库的命令在执行前,都会调用expiredIfNeeded对键进行检查。如果输入的键已经过期,那么将输入键从数据库中删除;否则不做任何处理。
- 定时删除
过期键的定时删除是由activeExpireCycle函数实现的,每当Redis服务器的周期性操作serverCron函数执行时,activeExpiredCycle函数就会被调用,它在规定的时间内,分多次遍历服务器中的各个数据库,从数据库的expires字典中随机检查一部分键的过期时间,并删除其中的过期键。
在csdn上面找了一段activeExpireCycle的伪代码
#默认每次检查的数据库数量 DEFAULT_DB_NUMBERS = 16 #默认每个数据库检查的键数量 DEFAULT_KEY_NUMBERS = 20 #全局变量,记录检查进度 current_db = 0 def activeExpireCycle(): # 初始化要检查的数据库数量 # 如果服务器的数据库数量比 DEFAULT_DB_NUMBERS 要小 # 那么以服务器的数据库数量为准 if server.dbnum < DEFAULT_DB_NUMBERS: db_numbers = server.dbnum else: db_numbers = DEFAULT_DB_NUMBERS # 遍历各个数据库 for i in range(db_numbers): # 如果current_db 的值等于服务器的数据库数量 # 这表示检查程序已经遍历了服务器的所有数据库一次 # 将current_db 重置为0 ,开始新的一轮遍历 if current_db == server.dbnum: current_db = 0 # 获取当前要处理的数据库 redisDb = server.db[current_db] # 将数据库索引增1 ,指向下一个要处理的数据库 current_db += 1 # 检查数据库键 for j in range(DEFAULT_KEY_NUMBERS): # 如果数据库中没有一个键带有过期时间,那么跳过这个数据库 if redisDb.expires.size() == 0: break #随机获取一个带有过期时间的键 key_with_ttl = redisDb.expires.get_random_key() # 检查键是否过期,如果过期就删除它 if is_expired(key_with_ttl): delete_key(key_with_ttl) # 已达到时间上限,停止处理 if reach_time_limit(): return
activeExpireCycle的处理过程是,每次遍历指定的db数,和每次查询的key的数,如果当前Redis的db_num数量大于默认的db数,则指定的db数为redis的db_num,并且遍历某个db时,会判断当前db有没有键设置过期时间,如果没有一个键设置了过期时间,那么跳过当前数据库;如果当前数据库中的过期key占key的填充率不足1%,则也跳过该数据库;如果当前数据库设置过期时间的key数小于默认的需要查询的key数,则设置当前数据库需要查询的key的数目为当前数据库的过期key的数目,否则随机获取一个带有过期键的key,判断key是否过期,过期则删除,并且进行广播,告诉从库删除,并将del操作写如果aof。