redis学习笔记->时间事件管理

一、redis时间缓存

在server结构体内,有两个成员,缓存下系统的当前时间

redisServer
{
    time_t unixtime;        /* Unix time sampled every cron cycle. */
    long long mstime;       /* Like 'unixtime' but with milliseconds resolution. */
}
在初始化iniServer()函数内,以及系统定时调用serverCron()函数内,会调用updateCachedTime()更新缓存的时间。
void updateCachedTime(void) {
    server.unixtime = time(NULL);
    server.mstime = mstime();
}

二、执行定时事件

server结构体内,有个 server.hz成员,时间事件serverCron()函数每次调用完会返回1000/server.hz,时间事件处理器将当前时间会加上这个值,作为下次触发serverCron()函数的时间点。这以为着,每秒钟,会调用server.hz次serverCron()函数。

serverCron()函数内会调用一些定时事件,比如检查客户端,统计命令次数等等。有的事件不需要每秒执行1000/server.hz次,因此需要使用run_with_period(milliseconds)宏,代表着每隔milliseconds秒执行一次该事件。

#define run_with_period(_ms_) if ((_ms_ <= 1000/server.hz) || !(server.cronloops%((_ms_)/(1000/server.hz))))
// 每隔100毫秒记录服务器执行命令的次数
    run_with_period(100) trackOperationsPerSecond();
其中server.cronloops再每次serverCron()函数返回之前会自增一次。

三、定时事件

检查客户端

    // 检查客户端,关闭超时客户端,并释放客户端多余的缓冲区
    clientsCron();

void clientsCron(void) {

    // 客户端数量
    int numclients = listLength(server.clients);

    // 要处理的客户端数量
    int iterations = numclients/(server.hz*10);

    // 至少要处理 50 个客户端
    if (iterations < 50)
        iterations = (numclients < 50) ? numclients : 50;

    while(listLength(server.clients) && iterations--) {
        redisClient *c;
        listNode *head;

        /* Rotate the list, take the current head, process.
         * This way if the client must be removed from the list it's the
         * first element and we don't incur into O(N) computation. */
        // 翻转列表,然后取出表头元素,这样一来上一个被处理的客户端会被放到表头
        // 另外,如果程序要删除当前客户端,那么只要删除表头元素就可以了
        listRotate(server.clients);
        head = listFirst(server.clients);
        c = listNodeValue(head);
        /* The following functions do different service checks on the client.
         * The protocol is that they return non-zero if the client was
         * terminated. */
        // 检查客户端,并在客户端超时时关闭它
        if (clientsCronHandleTimeout(c)) continue;
        // 根据情况,缩小客户端查询缓冲区的大小
        if (clientsCronResizeQueryBuffer(c)) continue;
    }
}


数据库操作

// 对数据库执行删除过期键,调整大小,以及主动和渐进式 rehash
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)
        // 清除模式为 CYCLE_SLOW ,这个模式会尽量多清除过期键
        activeExpireCycle(ACTIVE_EXPIRE_CYCLE_SLOW);

    /* Perform hash tables rehashing if needed, but only if there are no
     * other processes saving the DB on disk. Otherwise rehashing is bad
     * as will cause a lot of copy-on-write of memory pages. */
    // 在没有 BGSAVE 或者 BGREWRITEAOF 执行时,对哈希表进行 rehash
    if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
        /* We use global counters so if we stop the computation at a given
         * DB we'll be able to start from the successive in the next
         * cron loop iteration. */
        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;
                }
            }
        }
    }
}


还有定时记录日志,统计服务器命令,内存信息等等

你可能感兴趣的:(redis)