本篇继续解析单机数据库的实现,理解第二个属性expires。
Redis的过期删除采用了什么策略?过期键会被保存在更新后的RDB文件吗?主从节点对过期键的处理方式有什么不同?本篇将走进源码,寻找答案。
expires
该属性用于保存键的过期时间,Redis提供多种命令设置键的过期时间,但是最终都会将设置的数值通过相应函数转化为UNIX时间戳来保存,类型是long long。
这里涉及两方面内容,一个是过期判定,一个是过期删除。
过期判定
主要通过expireIfNeeded方法来判定,代码如下:
|
|
暂时隐去了涉及多节点的代码。
过期删除
过期删除的策略和之前分析字典实现时的rehash策略是类似的,都可以算是用存储开销来换取计算开销:实时的释放内存会增加CPU的计算负担。
所以Redis采用了称为惰性删除和定期删除的策略。
惰性删除策略
简单思路就是:键虽然过期了,但是不会立马删除它,而是在访问键的时候再处理。
也就是每次访问的时候调用expireIfNeeded
方法,如果过期了就进行删除操作dbDelete()并返回:
|
|
定期删除策略
简单思路就是:每隔一段时间执行一次删除。
该功能通过activeExpireCycle方法实现,在serverCron()内被调用:
|
|
过期键对RDB、AOF和复制的影响
RDB:
创建RDB文件时,程序会对键进行检查,过期的键不会被写入到更新后的RDB文件中。
AOF:
触发惰性删除或定期删除事件,程序会向AOF文件追加DEL命令。
复制:
假设现在进行可能发生惰性删除(定期删除类似)的操作,那么会调用expireIfNeeded(),在前文列出该方法源码的时候,本人暂时隐去了涉及多节点的代码
,这里显现:
|
|
server.masterhost != NULL
为true,说明是从节点,返回mstime() > when
的值,不会再进行后续删除的操作;
如果能执行到propagateExpire(db,key);
,说明是主节点且键是过期键,会通知其它从节点也要删除这个键,并在后面的代码中主动调用方法删除键;
这些代码说明了在复制条件下,删除过期键的原则:
- 从节点没有主动删除过期键的权利,应对客户端的请求,它只有“观察”的权利,返回的值可以告知客户端该键是否过期;
- 主节点在确认键是过期节点,并将在数据库中删除该键之前,会传播过期命令,通知从节点也删掉该键;
参考
Redis 设计与实现:国内解析Redis的开源资料;