redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db中,db是一个redisDb数组类型,每个元素都代表一个数据库(redisDb),而服务器内部又保存一个redisClient结构,它包含了一个redisDb指针,用来表示当前所用数据库.当我们想切换数据库时,只需修改这个指针即可.下面是它的数据结构代码
关于键值对增删改查的基本操作,不再叙述,这里要说的是读取操作会引起服务器键空间命中次数(hit)和不命中次数(miss),以及LRU(最后一次访问时间)的更新,如果读取时发现某个键已过期,则删之
定时删除占用CPU,影响服务器响应时间和吞吐量;惰性删除太占用空间,可能发生内存泄露,定期删除是两者的中和,服务器需要根据情况,合理的设置删除操作的执行时长和执行频率.
下面介绍下一些常见操作对过期键的处理(摘自redis设计与实现)
<img src="https://pic4.zhimg.com/v2-31d6a4bbc39ed0c866861678fdba0593_b.png" data-rawwidth="736" data-rawheight="256" class="origin_image zh-lightbox-thumb" width="736" data-original="https://pic4.zhimg.com/v2-31d6a4bbc39ed0c866861678fdba0593_r.png">到了这里,我们基本了解了Redis数据库,如果喜欢我的文章,请继续阅读
到了这里,我们基本了解了Redis数据库,如果喜欢我的文章,请继续阅读图解Redis之持久化篇
struct redisServer{
...
redisDb *db; //redisDb数组,表示服务器中所有的数据库
int dbnum; //数组大小,默认为16
...
};
typedef struct redisClient{
...
redisDb *db; //客户端当前所选数据库
...
}redisClient;
typedef struct redisDb {
int id; // 数据库ID标识
dict *dict; // 数据库键空间,存放着所有的键值对
dict *expires; // 键的过期时间
dict *watched_keys; // 被watch命令监控的key和相应client
long long avg_ttl; // 数据库内所有键的平均TTL(生存时间)
} redisDb;
代码中有个dict,这个字典(键空间)存放了数据库所有的键值对,它的键是字符串对象,值可以使Redis的5中任意对象之一.下面给出一个它的实例图(redis设计与实现p94)
<img src="https://pic1.zhimg.com/v2-b370640d45373fb966e49f946b548908_b.png" data-rawwidth="608" data-rawheight="314" class="origin_image zh-lightbox-thumb" width="608" data-original="https://pic1.zhimg.com/v2-b370640d45373fb966e49f946b548908_r.png"> 关于键值对增删改查的基本操作,不再叙述,这里要说的是读取操作会引起服务器键空间命中次数(hit)和不命中次数(miss),以及LRU(最后一次访问时间)的更新,如果读取时发现某个键已过期,则删之
关于键值对增删改查的基本操作,不再叙述,这里要说的是读取操作会引起服务器键空间命中次数(hit)和不命中次数(miss),以及LRU(最后一次访问时间)的更新,如果读取时发现某个键已过期,则删之
当修改一个值时,如果有客户端使用watch监视了某个键,那么服务器在被监视键修改后,会将这个key标记为脏(dirty),每修改一次,dirty加1;此外,如果服务器开启了通知功能,修改值后,服务器还会按照配置发送相应的数据库通知
好的介绍完键空间后我们一起聊聊键的生存和过期时间,以及过期键删除策略
- 设置键生存时间 EXPIRE key seconds, PEXPIRE key ms
- 设置过期时间: EXPIREAT unix时间戳(s) , PEXPIREAT unix时间戳(ms)
过期键删除策略
- 定时删除:通过设置定时器,在过期时立即删除
- 惰性删除:放任不管,但在获取键时发现过期,则删除
- 定期删除:每隔一段时间,检查一次数据库,删除过期键
定时删除占用CPU,影响服务器响应时间和吞吐量;惰性删除太占用空间,可能发生内存泄露,定期删除是两者的中和,服务器需要根据情况,合理的设置删除操作的执行时长和执行频率.
# 默认每次检查的数据库数量
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 函数的工作模式可以总结如下:
- 函数每次运行时,都从一定数量的数据库中取出一定数量的随机键进行检查, 并删除其中的过期键。
- 全局变量current db 会记录当前activeExpireCycle 函数检查的进度,并在下一次activeExpireCycle 函数调用时,接着上一次的进度进行处理。比如说,如果当前activeExpireCycle 函数在遍历10 号数据库时返回了,那么下次activeExpireCycle 函数执行时,将从11号数据库开始查找并删除过期键。
- 随着activeExpireCycle函数的不断执行,服务器中的所有数据库都会被检查一遍,这时函数将current_db变量重置为0,然后再次开始新一轮的检查工作
下面介绍下一些常见操作对过期键的处理(摘自redis设计与实现)
&amp;amp;lt;img src="https://pic4.zhimg.com/v2-31d6a4bbc39ed0c866861678fdba0593_b.png" data-rawwidth="736" data-rawheight="256" class="origin_image zh-lightbox-thumb" width="736" data-original="https://pic4.zhimg.com/v2-31d6a4bbc39ed0c866861678fdba0593_r.png"&amp;amp;gt;到了这里,我们基本了解了Redis数据库,如果喜欢我的文章,请继续阅读
到了这里,我们基本了解了Redis数据库,如果喜欢我的文章,请继续阅读图解Redis之持久化篇