redis 時間事件

時間事件保存在aeEventLoop->timeEventHead 以鏈表的方式進行存儲

/* Time event structure */
typedef struct aeTimeEvent {
     long long id; 					/* time event identifier. */
     long when_sec; 					/* seconds */
     long when_ms; 					/* milliseconds */
     aeTimeProc *timeProc;			//時間事件處理函數
     aeEventFinalizerProc *finalizerProc;
     void *clientData;
     struct aeTimeEvent *next;
 } aeTimeEvent;

時間事件API

添加時間事件

long long aeCreateTimeEvent(aeEventLoop *eventLoop, long long milliseconds,
        aeTimeProc *proc, void *clientData,
        aeEventFinalizerProc *finalizerProc)
{
    long long id = eventLoop->timeEventNextId++;
    aeTimeEvent *te;

    te = zmalloc(sizeof(*te));
    if (te == NULL) return AE_ERR;
te->id = id;
//微妙轉換成時間戳
aeAddMillisecondsToNow(milliseconds,&te->when_sec,&te->when_ms); 
    te->timeProc = proc;				//時間處理函數
    te->finalizerProc = finalizerProc;
    te->clientData = clientData;
    te->next = eventLoop->timeEventHead;	//insert 鏈表
    eventLoop->timeEventHead = te;
    return id;
}

刪除時間事件(by id)

int aeDeleteTimeEvent(aeEventLoop *eventLoop, long long id)
{
    aeTimeEvent *te, *prev = NULL;

    te = eventLoop->timeEventHead;
    while(te) {
        if (te->id == id) {
            if (prev == NULL)
                eventLoop->timeEventHead = te->next;
            else
                prev->next = te->next;
//刪除時候,執行的finalizerProc回調
            if (te->finalizerProc)
                te->finalizerProc(eventLoop, te->clientData);
            zfree(te);
            return AE_OK;
        }
        prev = te;
        te = te->next;
    }
    return AE_ERR; /* NO event with the specified ID found */
}

//搜索最近時間事件,遍歷鏈表

static aeTimeEvent *aeSearchNearestTimer(aeEventLoop *eventLoop)
{
    aeTimeEvent *te = eventLoop->timeEventHead;
    aeTimeEvent *nearest = NULL;

    while(te) {
        if (!nearest || te->when_sec < nearest->when_sec ||
                (te->when_sec == nearest->when_sec &&
                 te->when_ms < nearest->when_ms))
            nearest = te;
        te = te->next;
    }
    return nearest;
}

//時間事件處理函數

static int processTimeEvents(aeEventLoop *eventLoop) {
    int processed = 0;
    aeTimeEvent *te;
    long long maxId;
    time_t now = time(NULL);

    /* 如果時鐘被往回調整,定時jobs強制執行一遍     */
    if (now < eventLoop->lastTime) {
        te = eventLoop->timeEventHead;
        while(te) {
            te->when_sec = 0;
            te = te->next;
        }
    }
    eventLoop->lastTime = now;

    te = eventLoop->timeEventHead;
    maxId = eventLoop->timeEventNextId-1;
    while(te) {
        long now_sec, now_ms;
        long long id;

        if (te->id > maxId) {
            te = te->next;
            continue;
        }
        aeGetTime(&now_sec, &now_ms);
//超時了
        if (now_sec > te->when_sec ||
            (now_sec == te->when_sec && now_ms >= te->when_ms))
        {
            int retval;

            id = te->id;
/*回調定時任務函數,比如serverCron*/
            retval = te->timeProc(eventLoop, id, te->clientData);
            processed++;
            /*重置或者刪除*/
            if (retval != AE_NOMORE) {
                aeAddMillisecondsToNow(retval,&te->when_sec,&te->when_ms);
            } else {
                aeDeleteTimeEvent(eventLoop, id);
            }
            te = eventLoop->timeEventHead;
        } else {
            te = te->next;
        }
    }
    return processed;
}

serverCron

持續運行的redis需要定期對自身資源和狀態進行檢查和調整,serverCron就是做這件事的。

主要工作:

1 更新服務器各類統計,比如時間、內存佔用、數據庫佔用等情況

2 清理數據庫中過期的鍵值對

3 關閉和清理連接失效的客戶端

4 嘗試進行aof或rdb持久化操作

5 如果服務器是主服務器,那麼對從服務器進行定期同步

添加:

initServer -> aeCreateTimeEvent

if(aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL) == AE_ERR) {
redisPanic("Can't create the serverCron time event.");
	exit(1);
}

執行:

1 watch_dog機制,是爲了檢測系統超時調用。相應的配置watchdog_period,如果爲非0,那麼就是執行一遍網絡事件耗時超過給定值,那麼setitimer 就會釋放sigalarm信號, 生成coredump,可以看當前耗時堆棧。

源碼:

if (server.watchdog_period) watchdogScheduleSignal(server.watchdog_period);
void watchdogScheduleSignal(int period) {
     struct itimerval it;

     /* Will stop the timer if period is 0. */
     it.it_value.tv_sec = period/1000;
     it.it_value.tv_usec = (period%1000)*1000;
     /* Don't automatically restart. */
     it.it_interval.tv_sec = 0;
     it.it_interval.tv_usec = 0;
     setitimer(ITIMER_REAL, &it, NULL);
}

2 更新系統cache時間

updateCachedTime()

3 統計,採用循環數組方式,idx指向當前最新方式。

//平均命令數
trackInstantaneousMetric(REDIS_METRIC_COMMAND,server.stat_numcommands);
//平均網絡input
trackInstantaneousMetric(REDIS_METRIC_NET_INPUT,server.stat_net_input_bytes);
//平均網絡output
trackInstantaneousMetric(REDIS_METRIC_NET_OUTPUT,server.stat_net_output_bytes);

4 更新redis idle 時間

server.lruclock = getLRUClock();

5 記錄最大使用內存

if (zmalloc_used_memory() > server.stat_peak_memory)
server.stat_peak_memory = zmalloc_used_memory();

6 客戶端管理clientsCron

 ①處理超時客戶端 ② 客戶端緩衝區大小調整

7databasesCron 數據庫管理

發佈了83 篇原創文章 · 獲贊 8 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章