Redis 数据结构与内存管理策略(下) (3)

EXPIREAT 命令可以设置某个 key 在多少秒时间戳之后过期
PEXPIREAT 命令可以设置某个 key 在多少毫秒时间戳之后过期

PERSIST 命令可以移除键的过期时间

其实上述命令最终都会被转换成对 PEXPIREAT 命令。在 redisDb->expires 指向的 key 字典中维护着一个到期的毫秒时间戳。

TTL、PTTL 可以通过这两个命令查看某个 key 的过期秒、毫秒数。

redis 内部有一个 事件循环,这个事件循环会检查键的过期时间是否小于当前时间,如果小于则会删除这个键。

过期键删除策略

在使用 redis 的时候我们最关心的就是键是如何被删除的,如何高效的准时的删除某个键。其实 redis 提供了两个方案来完成这件事情。

redis 采用 惰性删除定期删除 双重删除策略。

当我们访问某个 key 的时候 redis 会检查它是否过期,这是惰性删除。

robj *lookupKeyRead(redisDb *db, robj *key) { robj *val; expireIfNeeded(db,key); val = lookupKey(db,key); if (val == NULL) server.stat_keyspace_misses++; else server.stat_keyspace_hits++; return val; } int expireIfNeeded(redisDb *db, robj *key) { mstime_t when = getExpire(db,key); mstime_t now; if (when < 0) return 0; /* No expire for this key */ if (server.loading) return 0; now = server.lua_caller ? server.lua_time_start : mstime(); if (server.masterhost != NULL) return now > when; /* Return when this key has not expired */ if (now <= when) return 0; /* Delete the key */ server.stat_expiredkeys++; propagateExpire(db,key); notifyKeyspaceEvent(REDIS_NOTIFY_EXPIRED,"expired",key,db->id); return dbDelete(db,key); }

redis 也会通过 事件循环 周期性的执行 key 的过期删除动作,这是定期删除。

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { /* Handle background operations on Redis databases. */ databasesCron(); } void databasesCron(void) { /* Expire keys by random sampling. Not required for slaves * as master will synthesize DELs for us. */ if (server.active_expire_enabled && server.masterhost == NULL) activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW); }

惰性删除 是每次只要有读取、写入都会触发惰性删除代码。周期删除 是由 redis EventLoop 来触发的。redis 内部很多维护性工作都是基于 EventLoop

AOFRDB 处理过期键策略

既然键会随时存在过期问题,那么涉及到持久化 redis 是如何帮我们处理的。

redis 使用 RDB 方式持久化时,每次持久化的时候就会检查这些即将被持久化的 key 是否已经过期,如果过期将直接忽略,持久化那些没有过期的键。当 redis 作为 master 主服务器 启动的时候,在载入 rdb 持久化键时也会检查这些键是否过期,将忽略过期的键,只载入没过期的键。

redis 使用 AOF 方式持久化时,每次遇到过期的 key redis 会追加一条 DEL 命令 到 AOF 文件,也就是说只要我们顺序载入执行 AOF 命令文件就会删除过期的键。

如果 redis 作为从服务器启动的化,它一旦与 master 主服务器 建立链接就会清空所有数据进行完整同步,当然新版本的 redis 支持 SYCN2 的半同步。如果是已经建立了 master/slave 主从同步之后,主服务器会发送 DEL 命令给所有从服务器执行删除操作。

Redis LRU 算法

在使用 redis 的时候我们会设置 maxmemory 选项,64 位的默认是 0 不限制。线上的服务器必须要设置的,要不然很有可能导致 redis 宿主服务器直接内存耗尽最后链接都上不去。

所以基本要设置两个配置:

maxmemory 最大内存阈值
maxmemory-policy 到达阈值的执行策略

可以通过 CONFIG GET maxmemory/maxmemory-policy 分别查看这两个配置值,也可以通过 CONFIG SET 去分别配置。

maxmemory-policy 有一组配置,可以用在很多场景下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzjfw.html