天天看點

Redis源碼解析--NET

    關于Redis資料:

    在接下來的日子裡,我會記錄下我對Redis源碼的一些認識,首先從Event driven programming library開始,沒有理由,如果有:那就是redis.h包含的非系統頭檔案從#include

一、NET分層

    Redis 網絡部分主要分四層:

Redis源碼解析--NET

圖1 NET分層圖

1、  TCP/Unix Socket層(Anet.h(117)、Anet.c(405))

(1)socket建立

    anetCreateSocket:建立TCP/Unix

socket,設定socket SO_REUSEADDR。

(2)socket屬性設定

    anetNonBlock:設定阻塞還是非阻塞。

    anetSetSendBuffer:設定發送buffer大小。

(3)Connect

    anetTcpGenericConnect:TCP Connect原始接口封裝,輸入IP位址和阻塞/非阻塞參數。

    anetTcpConnect:TCP阻塞連接配接。

    anetTcpNonBlockConnect:TCP非阻塞連接配接。

    anetUnixGenericConnect:Unix Connect原始接口封裝,輸入IP位址和阻塞/非阻塞參數。

    anetUnixConnect:Unix阻塞連接配接。

    anetUnixNonBlockConnect:Unix非阻塞連接配接。

(4)Listen

    anetListen:bind和listen(511原因請查Nginx)封裝。

    anetTcpServer:調用anetCreateSocket和anetListen監聽連接配接到來。

    anetUnixServer:調用anetCreateSocket和anetListen監聽連接配接到來。

(5)Accept

    anetGenericAccept:accept封裝,while直到accept成功或失敗才傳回。

    anetTcpAccept:調用anetGenericAccept,傳回fd,帶回IP和Port(函數參數)或錯誤。    

    anetUnixAccept:調用anetGenericAccept,傳回fd,或帶回錯誤(函數參數)。

(6)IP和host互轉

    anetPeerToString:由IPAddress->Host。

    anetResolve:由Host->IPAddresss。

(7)格式化error

    anetSetError:變長參數格式化,函數參數帶回格式化後error資訊。

2、  I/O模型層(Ae_select.c(72)、Ae_epoll.c(101)、Ae_kqueue.c(105))

    aeApiState:包含epoll fd句柄和Event指針的struct,epoll和kqueue基本一緻,而select是rfds和wfds集合及副本,具體見Ae_select.c代碼第7~12行。

    aeApiCreate:建立aeApiState,并以此初始化aeEventLoop(作用見後文)。epoll_create參數采用Linux kernel的hint值1024。

    aeApiFree:close epoll fd句柄,釋放malloc的aeApiState和aeEventLoop。

    aeApiAddEvent:通過mask修改或者添加fd對應Event的EPOLLIN或EPOLLOUT(epoll_ctl)。

    aeApiDelEvent:通過mask修改或者删除fd對應Event的EPOLLIN或EPOLLOUT(epoll_ctl)。

    aeApiPoll:epoll_wait等待核心傳回事件集合,填寫fire事件集合用于回調AE_READABLE和AE_WRITABLE對應函數。

    aeApiName:取得I/O模型字元串名稱("select"、"epoll"、"kqueue")。

3、  EventLoop層(Ae.h(117)、Ae.c(405))

(1)回調函數指針

    typedef void aeFileProc(struct aeEventLoop

*eventLoop, int fd, void *clientData, int mask);

    typedef int aeTimeProc(struct aeEventLoop

*eventLoop, long long id, void *clientData);

    typedef void aeEventFinalizerProc(struct

aeEventLoop *eventLoop, void *clientData);

    typedef void aeBeforeSleepProc(struct

aeEventLoop *eventLoop);

(2)Event Struct

    aeFileEvent:讀寫事件回調。

    aeTimeEvent:定時器事件回調。

    aeFiredEvent:觸發事件回調。

    aeEventLoop:主事件,包含讀寫事件、定時器事件、觸發事件清單。

(3)Event接口API

    aeCreateEventLoop:建立EventLoop。

    aeDeleteEventLoop:删除EventLoop。

    aeStop:置EventLoop stop标志。

    aeCreateFileEvent:添加關注事件。

    aeDeleteFileEvent:删除關注事件。

    aeGetFileEvents:擷取事件mask

    aeGetTime:擷取目前時間。

    aeAddMillisecondsToNow:增加毫秒數目前時間的秒和毫秒上。

    aeCreateTimeEvent:添加定時器事件。

    aeDeleteTimeEvent:删除定時器事件。

    SearchNearestTimer:搜尋最近的定時器。

    processTimeEvents:處理定時器事件,回調函數傳回AE_NOMORE(-1)則删除定時器,否則更新定時器時間為回調函數傳回的時間。

    aeProcessEvents:處理各種事件,用最近定時器即将到來的時間作為epoll_wait的逾時間,非常巧妙,如果馬上到就立即傳回,否則逾時間到再傳回。

    aeMain:主main,while循環直到eventLoop->stop不為0,在調用aeProcessEvents前,先回調aeBeforeSleepProc。

    aeGetApiName:擷取I/O模型字元串名稱("select"、"epoll"、"kqueue")。

    aeSetBeforeSleepProc:設定aeBeforeSleepProc回調函數。

4、  Networking層(Networking.c(1334))

    暫不表與網絡層無直接關系的接口函數。

    createClient:建立redisClient,有連接配接則設定fd為nonblocking,設定TCP_NODELAY,設定AE_READABLE對應的回調函數readQueryFromClient。

    prepareClientToWrite:在發送資料給用戶端時的預處理,即可以發送資料時設定AE_WRITABLE對應的回調函數sendReplyToClient;是REDIS_LUA_CLIENT時傳回REDIS_OK;是fake client或者slave或者setup write handler failed時傳回REDIS_ERR。

    acceptCommonHandler:調用createClient,校驗是否達到最大用戶端數。

    acceptTcpHandler:針對TCP依次調用anetTcpAccept、acceptCommonHandler。

    acceptUnixHandler:針對Unix,作用同acceptTcpHandler。

    freeClient:釋放redisClient,删除AE_READABLE、AE_WRITABLE,斷開master/slave,清除MULTI/EXEC

state等。

    sendReplyToClient:發送資料的回調函數,處理write邏輯。

    readQueryFromClient:接收資料的回調函數,處理read邏輯。

    還有一大票addReply…和get…,在此略去。

二、NET流程

    以redis-cli 從redis-server get資料為例來描述整體流程。

Redis源碼解析--NET

圖2 流程圖

    打完收工,

Redis源碼解析--NET

。。。