redis 数据删除策略和逐出算法 (2)

redis的定期删除是通过定时任务实现的,也就是定时任务会循环调用serverCron方法。然后定时检查过期数据的方法是databasesCron。定期删除的一大特点就是考虑了定时删除过期数据会占用cpu时间,所以每次执行databasesCron的时候会限制cpu的占用不超过25%。真正执行删除的是 activeExpireCycle方法。

时间事件

对于持续运行的服务器来说, 服务器需要定期对自身的资源和状态进行必要的检查和整理, 从而让服务器维持在一个健康稳定的状态, 这类操作被统称为常规操作(cron job

在 Redis 中, 常规操作由 redis.c/serverCron() 实现, 它主要执行以下操作

1 更新服务器的各类统计信息,比如时间、内存占用、数据库占用情况等。

2 清理数据库中的过期键值对。

3 对不合理的数据库进行大小调整。

4 关闭和清理连接失效的客户端。

5 尝试进行 AOF 或 RDB 持久化操作。

6 如果服务器是主节点的话,对附属节点进行定期同步。

7 如果处于集群模式的话,对集群进行定期同步和连接测试。

因为 serverCron() 需要在 Redis 服务器运行期间一直定期运行, 所以它是一个循环时间事件: serverCron() 会一直定期执行,直到服务器关闭为止。

在 Redis 2.6 版本中, 程序规定 serverCron() 每秒运行 10 次, 平均每 100 毫秒运行一次。 从 Redis 2.8 开始, 用户可以通过修改 hz选项来调整 serverCron() 的每秒执行次数, 具体信息请参考 redis.conf 文件中关于 hz 选项的说明

查看hz way1 : config get hz # "hz" "10" way2 : info server # server.hz 10 serverCron()

serverCron()会定期的执行,在serverCron()执行中会调用databasesCron() 方法(serverCron()还做了其他很多事情,但是现在不讨论,只谈删除策略)

int serverCron(struct aeEventLoop *eventLoop, long long id, void *clientData) { // 略去多无关代码 /* We need to do a few operations on clients asynchronously. */ // 检查客户端,关闭超时客户端,并释放客户端多余的缓冲区 clientsCron(); /* Handle background operations on Redis databases. */ // 对数据库执行各种操作 databasesCron(); /* !我们关注的方法! */ databasesCron()

在 databasesCron() 中 调用了 activeExpireCycle()方法,来对过期的数据进行处理。(在这里还会做一些其他操作~ 调整数据库大小,主动和渐进式rehash)

// 对数据库执行删除过期键,调整大小,以及主动和渐进式 rehash void databasesCron(void) { // 判断是否是主服务器 如果是 执行主动过期键清除 if (server.active_expire_enabled && server.masterhost == NULL) // 清除模式为 CYCLE_SLOW ,这个模式会尽量多清除过期键 activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW); // 在没有 BGSAVE 或者 BGREWRITEAOF 执行时,对哈希表进行 rehash if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) { static unsigned int resize_db = 0; static unsigned int rehash_db = 0; unsigned int dbs_per_call = REDIS_DBCRON_DBS_PER_CALL; unsigned int j; /* Don't test more DBs than we have. */ // 设定要测试的数据库数量 if (dbs_per_call > server.dbnum) dbs_per_call = server.dbnum; /* Resize */ // 调整字典的大小 for (j = 0; j < dbs_per_call; j++) { tryResizeHashTables(resize_db % server.dbnum); resize_db++; } /* Rehash */ // 对字典进行渐进式 rehash if (server.activerehashing) { for (j = 0; j < dbs_per_call; j++) { int work_done = incrementallyRehash(rehash_db % server.dbnum); rehash_db++; if (work_done) { /* If the function did some work, stop here, we'll do * more at the next cron loop. */ break; } } } } } activeExpireCycle()

大致流程如下

1 遍历指定个数的db(默认的 16 )进行删除操作

2 针对每个db随机获取过期数据每次遍历不超过指定数量(如20),发现过期数据并进行删除。

3 如果有多于25%的keys过期,重复步骤 2

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

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